线程
v 线程是程序执行的一条路径, 一个进程中可以包含多条线程
v 一个应用程序可以理解成就是一个进程
v 多线程并发执行可以提高程序的效率, 可以同时完成多项工作
public class Demo01 { public static void main(String[] args) { /*JVM的启动是多线程的吗?【面试题】*/
System.out.println("AAAAA"); System.out.println("BBBBB"); System.out.println("CCCCC"); System.out.println("DDDDD");
//打印线程名称 System.out.println(Thread.currentThread());//主线程
for(int i = 0;i<2;i++){ new Student(); System.gc();//启动垃圾回收 } } } class Student{ //被垃圾回收器回收时,会调用 //对象从内存释放时,会调用 @Override protected void finalize() throws Throwable { // TODO Auto-generated method stub System.out.println("student 被回收了..."); //打印线程名称 System.out.println(Thread.currentThread());//子线程 } }
|
使用步骤:
1.定义类继承Thread
2.重写run方法
3.把新线程要做的事写在run方法中
4.创建线程对象
5.开启新线程, 内部会自动执行run方法
代码:
public class Demo01 { public static void main(String[] args) { /*主线程,程序员不能创建,程序员只能创建子线程*/
//1.创建子线程对象 MyThread t1 = new MyThread();
/**不能通过下面的方式来执行任务 * 因为这种试的任务是在主线程执行的*/ //t1.run();
//2.正确的执行任务的方式,调用start,内部会开启新线程,调用run方法 t1.start();
//3.再创建子线程 MyThread t2 = new MyThread(); t2.start();
//4.循环创建子线程 for(int i=0;i<10;i++){ MyThread th = new MyThread(); th.start(); }
}
}
class MyThread extends Thread{
@Override public void run() { System.out.println("银行信用卡还款短信任务..." + Thread.currentThread());
System.out.println("线程名称" + this.getName()); } }
|
实现步骤:
1.定义类实现Runnable接口
2.实现run方法
3.把新线程要做的事写在run方法中
4.创建自定义的Runnable的子类对象,创建Thread对象传入Runnable
5.调用start()开启新线程, 内部会自动调用Runnable的run()方法
代码:
public class Demo01 { public static void main(String[] args) { /* 线程实现的方式 (2) - 定义类实现Runnable接口 //1.创建runable对象 BankTask task = new BankTask();
//2.创建Thread对象 Thread t1 = new Thread(task);
//3.启动线程 t1.start();
//4.再开启2个线程 Thread t2 = new Thread(task); t2.start();
Thread t3 = new Thread(task); t3.start(); } }
class BankTask implements Runnable{ @Override public void run() { // TODO Auto-generated method stub System.out.println("银行储蓄卡自动结算利息任务..." + Thread.currentThread());
//System.out.println("线程名称:" + this.getName()); System.out.println("线程名称:" +Thread.currentThread().getName()); }
} |
区别:
继承Thread
实现Runnable接口
public static void main(String[] args) { //匿名内部类实现线程的两种方式 /*Thread t1 = new Thread(){ @Override public void run() { System.out.println("任务1...." + Thread.currentThread()); } }; t1.start();*/
new Thread(){ public void run() { System.out.println("任务1...." + Thread.currentThread()); }; }.start();
/*Thread t2 = new Thread(new Runnable() { @Override public void run() { System.out.println("任务2...." + Thread.currentThread()); } }); t2.start();*/ new Thread(new Runnable() { @Override public void run() { System.out.println("任务2...." + Thread.currentThread()); } }).start(); } |
public class Demo01 { public static void main(String[] args) { /* 获取线程名字和设置名字(掌握) //1.获取主线程对象 Thread mainThread = Thread.currentThread(); System.out.println(Thread.currentThread()); System.out.println(mainThread); System.out.println("名称:" + mainThread.getName());
//2.设置线程的名称 mainThread.setName("主线程"); System.out.println(mainThread);
//3.设置子线程的名称 MyThread myThread = new MyThread("子线程1"); myThread.start(); } }
class MyThread extends Thread{
public MyThread(String name) { super(name); }
@Override public void run() { System.out.println("银行代发工资任务..." + Thread.currentThread()); } } |
public class Demo01 {
public static void main(String[] args) { //获取当前线程的对象(掌握) Thread mainThread = Thread.currentThread(); mainThread.setName("主线程"); //打印主线程对象 System.out.println(mainThread);
//打印主线程对象类名 System.out.println(mainThread.getClass());
System.out.println("================"); //开启子线程 MyThread mt = new MyThread(); mt.start(); } }
class MyThread extends Thread{ @Override public void run() { System.out.println("任务..."); Thread subThread = Thread.currentThread(); //打印子线程对象 System.out.println(subThread); //打印子线程对象类名 System.out.println(subThread.getClass().getName());
} } |
主线程休眠
/*** 主线程休眠 */ public static void test1() { for(int i=0;i<10;i++){ System.out.println(i); //休眠【暂停】 try { Thread.sleep(1000);//主线程休眠 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("AAAAAAAAAAAAAAAAAA"); } |
子线程休眠
/** * 子线程休眠 */ public static void test2() { //子线程休眠 new Thread(){ public void run() { for(int i=0;i<10;i++){ System.out.println(Thread.currentThread() + " " + i); //休眠 try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; }.start();
System.out.println("AAAAAAAAAAAAAAAA"); } |
线程
v 线程是程序执行的一条路径, 一个进程中可以包含多条线程
v 一个应用程序可以理解成就是一个进程
v 多线程并发执行可以提高程序的效率, 可以同时完成多项工作
public class Demo01 { public static void main(String[] args) { /*JVM的启动是多线程的吗?【面试题】*/
System.out.println("AAAAA"); System.out.println("BBBBB"); System.out.println("CCCCC"); System.out.println("DDDDD");
//打印线程名称 System.out.println(Thread.currentThread());//主线程
for(int i = 0;i<2;i++){ new Student(); System.gc();//启动垃圾回收 } } } class Student{ //被垃圾回收器回收时,会调用 //对象从内存释放时,会调用 @Override protected void finalize() throws Throwable { // TODO Auto-generated method stub System.out.println("student 被回收了..."); //打印线程名称 System.out.println(Thread.currentThread());//子线程 } }
|
使用步骤:
1.定义类继承Thread
2.重写run方法
3.把新线程要做的事写在run方法中
4.创建线程对象
5.开启新线程, 内部会自动执行run方法
代码:
public class Demo01 { public static void main(String[] args) { /*主线程,程序员不能创建,程序员只能创建子线程*/
//1.创建子线程对象 MyThread t1 = new MyThread();
/**不能通过下面的方式来执行任务 * 因为这种试的任务是在主线程执行的*/ //t1.run();
//2.正确的执行任务的方式,调用start,内部会开启新线程,调用run方法 t1.start();
//3.再创建子线程 MyThread t2 = new MyThread(); t2.start();
//4.循环创建子线程 for(int i=0;i<10;i++){ MyThread th = new MyThread(); th.start(); }
}
}
class MyThread extends Thread{
@Override public void run() { System.out.println("银行信用卡还款短信任务..." + Thread.currentThread());
System.out.println("线程名称" + this.getName()); } }
|
实现步骤:
1.定义类实现Runnable接口
2.实现run方法
3.把新线程要做的事写在run方法中
4.创建自定义的Runnable的子类对象,创建Thread对象传入Runnable
5.调用start()开启新线程, 内部会自动调用Runnable的run()方法
代码:
public class Demo01 { public static void main(String[] args) { /* 线程实现的方式 (2) - 定义类实现Runnable接口 //1.创建runable对象 BankTask task = new BankTask();
//2.创建Thread对象 Thread t1 = new Thread(task);
//3.启动线程 t1.start();
//4.再开启2个线程 Thread t2 = new Thread(task); t2.start();
Thread t3 = new Thread(task); t3.start(); } }
class BankTask implements Runnable{ @Override public void run() { // TODO Auto-generated method stub System.out.println("银行储蓄卡自动结算利息任务..." + Thread.currentThread());
//System.out.println("线程名称:" + this.getName()); System.out.println("线程名称:" +Thread.currentThread().getName()); }
} |
区别:
继承Thread
实现Runnable接口
public static void main(String[] args) { //匿名内部类实现线程的两种方式 /*Thread t1 = new Thread(){ @Override public void run() { System.out.println("任务1...." + Thread.currentThread()); } }; t1.start();*/
new Thread(){ public void run() { System.out.println("任务1...." + Thread.currentThread()); }; }.start();
/*Thread t2 = new Thread(new Runnable() { @Override public void run() { System.out.println("任务2...." + Thread.currentThread()); } }); t2.start();*/ new Thread(new Runnable() { @Override public void run() { System.out.println("任务2...." + Thread.currentThread()); } }).start(); } |
public class Demo01 { public static void main(String[] args) { /* 获取线程名字和设置名字(掌握) //1.获取主线程对象 Thread mainThread = Thread.currentThread(); System.out.println(Thread.currentThread()); System.out.println(mainThread); System.out.println("名称:" + mainThread.getName());
//2.设置线程的名称 mainThread.setName("主线程"); System.out.println(mainThread);
//3.设置子线程的名称 MyThread myThread = new MyThread("子线程1"); myThread.start(); } }
class MyThread extends Thread{
public MyThread(String name) { super(name); }
@Override public void run() { System.out.println("银行代发工资任务..." + Thread.currentThread()); } } |
public class Demo01 {
public static void main(String[] args) { //获取当前线程的对象(掌握) Thread mainThread = Thread.currentThread(); mainThread.setName("主线程"); //打印主线程对象 System.out.println(mainThread);
//打印主线程对象类名 System.out.println(mainThread.getClass());
System.out.println("================"); //开启子线程 MyThread mt = new MyThread(); mt.start(); } }
class MyThread extends Thread{ @Override public void run() { System.out.println("任务..."); Thread subThread = Thread.currentThread(); //打印子线程对象 System.out.println(subThread); //打印子线程对象类名 System.out.println(subThread.getClass().getName());
} } |
主线程休眠
/*** 主线程休眠 */ public static void test1() { for(int i=0;i<10;i++){ System.out.println(i); //休眠【暂停】 try { Thread.sleep(1000);//主线程休眠 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("AAAAAAAAAAAAAAAAAA"); } |
子线程休眠
/** * 子线程休眠 */ public static void test2() { //子线程休眠 new Thread(){ public void run() { for(int i=0;i<10;i++){ System.out.println(Thread.currentThread() + " " + i); //休眠 try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; }.start();
System.out.println("AAAAAAAAAAAAAAAA"); } |
//火车站卖票【问题】 /** * 湖南到广州火车票:今天13:00 ,100张 * 火车站有4个窗口在同时卖票,要保证一张票只能被卖一次 * * 搞4个线程表示4个窗口 * * 通过加锁可以解决被多次卖同一张票的问题 * * 使用同步代码块 */
//创建卖票的任务 TicketTask task = new TicketTask();
//A窗口 Thread t1 = new Thread(task); t1.setName("窗口A"); //B窗口 Thread t2 = new Thread(task); t2.setName("窗口B"); //C窗口 Thread t3 = new Thread(task); t3.setName("窗口C"); //D窗口 Thread t4 = new Thread(task); t4.setName("窗口D");
//开启线程 t1.start(); t2.start(); t3.start(); t4.start(); |
class TicketTask implements Runnable{ //只有100张票 int ticket = 100; @Override public synchronized void run() { //卖票 while (true) { if (ticket <= 0) { System.out.println("不好意思,票已经卖完了..."); break; } else { System.out.println(Thread.currentThread() + "恭喜你卖到票,票号" + ticket); ticket--; } } }
/*@Override public void run() { // TODO Auto-generated method stub *//** * 同步代码换括号里参数可以传任意对象 * this是一个锁对象 * 不同的一把锁,卖相同的票总是还是存在 *//*
//卖票 while (true) { synchronized (String.class) {// 同步:加锁 if (ticket <= 0) { System.out.println("不好意思,票已经卖完了..."); break; } else { System.out.println(Thread.currentThread() + "恭喜你卖到票,票号" + ticket); ticket--; } } } }*/
/*@Override public void run() { // TODO Auto-generated method stub *//** * 同步代码换括号里参数可以传任意对象 *//* synchronized (this) { //卖票 while(true){ if(ticket <= 0){ System.out.println("不好意思,票已经卖完了..."); break; }else{ System.out.println(Thread.currentThread() + "恭喜你卖到票,票号" + ticket); ticket --; } } } }*/ } |
/** * 1.锁问题: * 同步中,锁最好同一个对象,如果不是同一对象,还是会有线程安全问题 * 锁:this,代表当前对象 * 锁:如果 new 对象,就不是同一把锁 * 锁:字节码对象 String.class,内存中,只有一个字节码对象 * 开发中:一般都是this * * 2.在方法内部声明synchronized的就是 “同步代码块” * * 3.在声明方法的时候,添加 synchronized,就是同步方法 * 》如果是非静态方法,锁就是this * 》如果是静态方法,锁就当前类的字节码对象 * //TicketTask.class public static synchronized void test1(){} * * 4.同步使用的建议: * 同步加锁的时候,尽量让锁住的代码范围小一点,这样可以让其它线程等待时间少一点,性能高 * */ |
public class Demo { static String s1 = "筷子左"; static String s2 = "筷子右"; public static void main(String[] args) { new Thread(){ public void run() { while(true){ synchronized (s1) { System.out.println("线程A 拿到" + s1 + " 等待" + s2); synchronized (s2) { System.out.println("线程A 拿到" + s2 + " 开吃"); } } } }; }.start();
new Thread(){ public void run() { while(true){ synchronized (s2) { System.out.println("线程B 拿到" + s2 + " 等待" + s1); synchronized (s1) { System.out.println("线程B 拿到" + s1 + " 开吃"); } } } }; }.start(); } } |
1》声明一个类,类中有一个静态属性,类型与类名相同
2》把空参构造方法声明为私有
3》在类中提供一个公共静态访问方法来返回该对象实例
写法一 饿汉式 |
class Singleton{ private static Singleton instance = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return instance; } } |
写法二 懒汉式 |
class Singleton{ private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } } |
写法三 另一种简单 |
class Singleton{ public static final Singleton instance = new Singleton(); private Singleton(){} } |
Runtime r = Runtime.getRuntime();
r.exec("shutdown -s -t 300");//300秒后关机
r.exec("shutdown -a"); //取消关机
public void schedule(TimerTask task, long delay)
public void schedule(TimerTask task, long delay, long period)
public void schedule(TimerTask task, Date firstTime, long period)
public static void test3() { /**定时器的细节 * 1.定时器在子线程中执行 * 2.timer.cancel(); 取消定时器 */
Timer timer = new Timer(); timer.schedule(new TimerTask() { int count = 5; @Override public void run() { // TODO Auto-generated method stub System.out.println("任务A:" + count +"..." + Thread.currentThread()); count --; if(count == 0){ //取消定时器 timer.cancel(); } } }, 1000,2000);
//timer.cancel();//主线程 } |
多个线程并发执行时, 在默认情况下CPU是随机切换线程的,如果我们希望他们有规律的执行, 就可以使用通信, 例如每个线程执行一次打印
》如果希望线程等待, 就调用wait()
》如果希望唤醒等待的线程, 就调用notify();
notify是随机唤醒一个线程
notifyAll是唤醒所有线程
》这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用
》如果方法中没有同步锁,会有异常IllegalMonitorStateException
public class Demo01 { public static void main(String[] args) { //1.创建任务对象 MyTask task = new MyTask();
//2.开启两个线程执行2个任务 new Thread(){ public void run() { while(true){ try { task.task1(); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); }
try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; }.start();
new Thread(){ public void run() { while(true){ try { task.task2(); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; }.start(); } }
class MyTask{
//标识 1:可以执行任务1,2:可以执行任务2 int flag = 1;
public synchronized void task1() throws InterruptedException{ if(flag != 1){ this.wait();//当前线程等待 }
System.out.println("1.银行信用卡自动还款任务..."); flag = 2; this.notify();//唤醒其它线程
}
public synchronized void task2() throws InterruptedException{
if(flag != 2){ this.wait();//线程等待 }
System.out.println("2.银行储蓄卡自动结算利息任务..."); flag = 1; this.notify();//唤醒其它线程 } }
|
public class Demo01 { public static void main(String[] args) { //三个线程间的通讯 MyTask task = new MyTask(); new Thread(){ public void run() { while(true){ try { task.task1(); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; }.start(); new Thread(){ public void run() { while(true){ try { task.task2(); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; }.start(); new Thread(){ public void run() { while(true){ try { task.task3(); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; }.start(); } }
class MyTask{
//标识 1:可以执行任务1,2:可以执行任务2, 3:可以执行任务3 int flag = 1;
public synchronized void task1() throws InterruptedException{ if(flag != 1){ this.wait();//当前线程等待 //this.wait(timeout); }
System.out.println("1.银行信用卡自动还款任务..."); flag = 2; //this.notify();//唤醒随机线程 this.notifyAll();//唤醒所有等待线程
}
public synchronized void task2() throws InterruptedException{
if(flag != 2){ this.wait();//线程等待 }
System.out.println("2.银行储蓄卡自动结算利息任务..."); flag = 3; //this.notify();//唤醒其它线程 this.notifyAll(); //Thread.sleep(millis); }
public synchronized void task3() throws InterruptedException{ if(flag != 3){ this.wait();//线程等待 }
System.out.println("3.银行短信提醒任务..."); flag = 1; //this.notify();//唤醒其它线程 this.notifyAll(); } } |
1.在同步代码块中,用哪个对象锁,就用哪个对象调用wait方法
2.为什么wait方法和notify方法定义在Object这类中?
因为锁对象可以是任意对象,Object是所有的类的基类,所以wait方法和notify方法需要定义在Object这个类中
3.sleep方法和wait方法的区别?
》sleep方法必须传入参数,参数就是时间,时间到了自动醒来
》wait方法可以传入参数也可以不传入参数,传入参数就是在参数的时间结束后等待,不传入参数就是直接等待
》sleep方法在同步函数或同步代码块中,不释放锁,睡着了也抱着锁睡
》wait方法在同步函数或者同步代码块中,释放锁
/** * 互斥锁的使用步骤 * 1.创建互斥锁对象 * 2.创建3个Condition * 3.加锁、解锁 * 4.线程等待-Condition的await方法 * 5.线程唤醒-Condition的signal方法 * @author gyf * */ class MyTask{ //创建互斥锁对象 ReentrantLock rl = new ReentrantLock(); //创建3个Condition Condition c1 = rl.newCondition(); Condition c2 = rl.newCondition(); Condition c3 = rl.newCondition();
//标识 1:可以执行任务1,2:可以执行任务2, 3:可以执行任务3 int flag = 1;
public void task1() throws InterruptedException{ rl.lock();//加锁 if(flag != 1){ c1.await();//当前线程等待 }
System.out.println("1.银行信用卡自动还款任务..."); flag = 2;
//指定唤醒线程2 c2.signal(); rl.unlock();//解锁 }
public void task2() throws InterruptedException{ rl.lock(); if(flag != 2){ c2.await();//线程等待 }
System.out.println("2.银行储蓄卡自动结算利息任务..."); flag = 3;
//唤醒线程3 c3.signal(); rl.unlock(); }
public void task3() throws InterruptedException{ rl.lock(); if(flag != 3){ c3.await();//线程等待 }
System.out.println("3.银行短信提醒任务..."); flag = 1;
//唤醒线程1 c1.signal(); rl.unlock(); } } |
1.Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
2.默认情况下,所有的线程都属于主线程组。
3.public final ThreadGroup getThreadGroup() 通过线程对象获取他所属于的组
4.public final String getName() 通过线程组对象获取组的名字
5.我们也可以给线程设置分组ThreadGroup(String name) 创建线程组对象并给其赋值名字
Thread(ThreadGroup?group, Runnable?target, String?name)
/** * 掌握: * 1.如何获取一个线程所属的线程组 * 2.如果在创建一个子线程时,设置它所属的线程组 * @author gyf * */ public class Demo01 { public static void main(String[] args) { //主线程 Thread mainThread = Thread.currentThread(); /** * [main,5,main] * main:线程名称 * 5:代先级 * main:当前线程所属的组名 */ System.out.println("线程:" + mainThread);
//获取线程的“线程组”对象 ThreadGroup tg = mainThread.getThreadGroup(); System.out.println("线程组:" + tg.getName());
//创建子线程 Thread t1 = new Thread(){ @Override public void run() { System.out.println("线程A..."); } }; //t1.start(); System.out.println("t1子线程的线程组:" + t1.getThreadGroup());
//创建一个线程组 ThreadGroup abcGroup = new ThreadGroup("abc组"); //创建子线程对象 Thread t2 = new Thread(abcGroup, new Runnable() {
@Override public void run() { // TODO Auto-generated method stub System.out.println("线程B"); } }); System.out.println("t2子线程的线程组:" + t2.getThreadGroup()); } }
|
程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池
1.JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newSingleThreadExecutor()
2. 这些方法的返回值是ExecutorService对象,该对象表示一个线程池,
可以执行Runnable对象或者Callable对象代表的线程。
它提供了如下方法
Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)
3.使用步骤:
1.创建线程池对象
2.创建Runnable实例
3.提交Runnable实例
4.关闭线程池es.shutdown();
4.Runnable和Callable的区别
Runnable的run方法没有返回值
Callable的call方法有返回值,一般返回值也没用
public class Demo01 { public static void main(String[] args) { //案例:10个线程完成10个洗车任务 /*for(int i = 0;i<10;i++){ new Thread(){ public void run() { System.out.println("洗车任务 " + Thread.currentThread()); }; }.start(); }*/
//案例:5个线程完成10个洗车的任务 //1.创建线程池 ExecutorService es = Executors.newFixedThreadPool(5);
//2.添加任务-方式一 /*for(int i=0;i<10;i++){ es.submit(new Runnable() { @Override public void run() { System.out.println("洗车任务 " + Thread.currentThread()); } }); }*/
//3.添加任务-方式二 for(int i=0;i<10;i++){ es.submit(new MyTask()); }
} }
class MyTask implements Callable<Integer>{
@Override public Integer call() throws Exception { System.out.println("洗车任务 " + Thread.currentThread()); return 110; }
}
|
多线程 java 同步 、锁 、 synchronized 、 Thread 、 Runnable
原文:https://www.cnblogs.com/2eggs/p/12579373.html