v# 1. 线程基本概念
(1)单核CPU实现多任务;(2)同一个CPU,在某个时刻,多个任务交替执行;CPU速度很快,造成“QQ”和“迅雷”貌似同时执行的错觉;
(1)在同一个时刻多个任务同时执行,多核CPU可以实现并行;
获取当前电脑Cpu数量
- 当一个类继承了Thread类,该类就可以当作线程使用;
- Thread类实现了Runnable接口的run方法
- 重写run方法,实现自己的业务逻辑
- 调用start()方法会调用run()方法
- cat调用start()方法,进入到Thread类的start()方法,start()方法调用start0()方法;
- 进入到Thread类中的start()方法;start0()是本地方法,JVM调用,用C/C++编写;
- 假如一个A类继承了B类,那么它就不能再继承Thread类,这个时候让A类实现Runable接口,同样能实现线程;
- Runable接口里没有start()方法,只有个run方法;
解决方案:dog对象赋给了Thread类中的target,thread.start()方法调用start0()方法,start0()方法调用本类的run方法,再调用target的run方法;
用代码模拟实现Runnable接口实现线程的机制;
public class Thread02 {public static void main(String[] args) {Tiger tiger = new Tiger();//实现了Runnable接口ThreadProxy threadProxy = new ThreadProxy(tiger);threadProxy.start();}
}
实现步骤: 先创建一个Proxy类,继承Runnable
class ThreadProxy implements Runnable {//把Proxy类当作 ThreadProxy 线程代理private Runnable target = null;@Overridepublic void run() {if (target != null) {target.run();//动态绑定(运行类型Tiger)}}public ThreadProxy(Runnable target) {this.target = target;}public void start() {start0();//真正实现多线程的方法}public void start0() {run();}
}
class Tiger extends Animal implements Runnable{@Overridepublic void run() {System.out.println("老虎发威~~");}
}
两个子线程会交替执行
在这里,主线程看不到
sleep()要在–tickets前面才能超卖
public class SellTicket {public static void main(String[] args) {/*SellTicket1 sellTicket1 = new SellTicket1();SellTicket1 sellTicket2 = new SellTicket1();SellTicket1 sellTicket3 = new SellTicket1();sellTicket1.start();sellTicket2.start();sellTicket3.start();*/SellTicket1 sellTicket1 = new SellTicket1();Thread thread1 = new Thread(sellTicket1);Thread thread2 = new Thread(sellTicket1);Thread thread3 = new Thread(sellTicket1);thread1.start();thread2.start();thread3.start();}
}class SellTicket1 extends Thread {//private static int tickets = 100;private int tickets = 100;int count = 0;@Overridepublic void run() {while (true) {if (tickets <= 0) {break;}System.out.println("窗台:" + Thread.currentThread().getName() +"出售了" + (++count) + "张票,剩余票数:" + (--tickets));try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}
}
启动一个线程t,要求在main线程中去停止线程t
解决方案:在主线程中通过Setter方法将loop变量设置为false
方法名 | 作用 |
---|---|
setName | 设置线程名称 |
getName | 获取线程名称 |
setPriority | 设置线程优先级 |
getPriority | 获取线程优先级 |
interrupt | 中断线程 |
public class ThreadMethod_ {public static void main(String[] args) throws InterruptedException {T t = new T();t.setName("赵志伟");//设置线程名称t.setPriority(Thread.MIN_PRIORITY);//设置线程优先级t.start();//启动了子线程System.out.println(t.getName());//获取线程名称//主线程打印5个hi,然后就中断子线程的休眠for (int i = 0; i < 5; i++) {Thread.sleep(1000);System.out.println("hi~~" + i);}System.out.println(t.getName() + "线程的优先级" + t.getPriority());t.interrupt();//执行到interrupt()方法时,中断线程的休眠}
}class T extends Thread {@Overridepublic void run() {while (true) {for (int i = 0; i < 100; i++) {//获取当前线程的名称System.out.println(Thread.currentThread().getName() + " 吃包子~~" + i);}try {System.out.println(Thread.currentThread().getName() + " 正在休眠中~~");Thread.sleep(20 * 1000);} catch (InterruptedException e) {//当该线程执行到一个interrupt 方法时,就会catch 一个异常,可以加入自己的业务代码// InterruptedException捕获了一个中断异常System.out.println(Thread.currentThread().getName() + "被中断了");}}}
}
yield:线程的礼让,让出cpu,让其它线程执行,但礼让的时间不确定,所以不一定礼让成功;
join:线程插队,一旦插入成功,则先执行完插入的线程的所有的任务;
public class Thread03 {public static void main(String[] args) throws InterruptedException {T t = new T();Thread thread = new Thread(t);thread.start();for (int i = 1; i <= 20; i++) {Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + "(小弟)吃了" + i + "个");if (i == 10) {System.out.println("main线程(小弟)让子线程(大哥)先吃");
// thread.join();//子线程(大哥)插队,大哥吃完小弟再吃Thread.yield();//main线程(小弟)礼让,不一定成功...}}}
}class T implements Runnable {private int count = 0;private boolean loop = true;@Overridepublic void run() {while (loop) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("子线程(老大)吃了" + (++count) + "个");if (count == 20) {//吃到20个结束System.out.println("子线程(大哥)吃完了,main线程(小弟)继续吃");break;}}}public void setLoop(boolean loop) {this.loop = loop;}
}
public class ThreadMethodExercise {public static void main(String[] args) throws InterruptedException {T1 t1 = new T1();Thread thread = new Thread(t1);for (int i = 1; i <= 10; i++) {Thread.sleep(1000);System.out.println("main线程:hi " + i);if (i == 5) {thread.start();thread.join();//子线程启动后直接插队}}}
}class T1 implements Runnable {private int count;@Overridepublic void run() {while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("子线程: hello " + (++count));if (count == 10) {break;}}}
}
用户线程:也叫工作线程、当线程的任务执行完或通知方式结束;
守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束;
常见的守护线程:垃圾回收机制;
主线程结束,子线程并不会结束;如果我们希望主线程结束时,子线程也结束,可以将子线程设置为守护线程;
public class ThreadMehod03 {public static void main(String[] args) {MyDaemonThread myDaemonThread = new MyDaemonThread();Thread thread = new Thread(myDaemonThread);thread.setDaemon(true);//将子线程设置为守护线程thread.start();for (int i = 1; i <= 10; i++) {System.out.println("主线程" + Thread.currentThread().getName() + i);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}
}class MyDaemonThread implements Runnable {@Overridepublic void run() {for (; ; ) {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("子线程" + Thread.currentThread().getName());}}
}
public class ThreadState_ {public static void main(String[] args) throws InterruptedException {T2 t2 = new T2();Thread thread = new Thread(t2);System.out.println(thread.getName() + "状态 " + thread.getState());//NEWthread.start();//子线程和主线程同时执行/*for (int i = 0; i < 10; i++) {Thread.sleep(1000);//主线程休眠、主线程输出System.out.println(thread.getName() + "状态 " + thread.getState());//RUNNABLE}*/while (Thread.State.TERMINATED != thread.getState()) {Thread.sleep(1000);System.out.println(thread.getName() + "状态 " + thread.getState());//RUNNABLE、TIMED_WAITING}System.out.println(thread.getName() + "状态 " + thread.getState());//TERMINATED}
}class T2 implements Runnable {@Overridepublic void run() {while (true) {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + " " + i);//子线程输出try {Thread.sleep(1000);//子线程休眠} catch (InterruptedException e) {e.printStackTrace();}}break;}}
}
Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性;
每个对象都对应一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象;
关键字synchronized来与对象的互斥锁联系,当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问;
同步的局限性:会导致程序的执行效率降低;
同步方法(非静态的)的锁可以是this,也可以是其它对象(要求是同一个对象)
同步方法(静态的)的锁为当前类本身;
方法上加锁、代码块上加锁;
同步方法如果没有使用static修饰,默认锁对象为this;
如果方法使用static修饰,默认锁对象:当前类.class; 如果想在静态方法中,实现一个同步代码块,写类本身;
public class DeadLock_ {public static void main(String[] args) {DeadLockDemo deadLockDemo = new DeadLockDemo(true);deadLockDemo.setName("A线程");deadLockDemo.start();DeadLockDemo deadLockDemo1 = new DeadLockDemo(false);deadLockDemo1.setName("B线程");deadLockDemo1.start();}
}class DeadLockDemo extends Thread {static Object o1 = new Object();//保证多线程,共享一个对象,使用staticstatic Object o2 = new Object();boolean flag;public DeadLockDemo(boolean flag) {//构造器this.flag = flag;}@Overridepublic void run() {//(1)如果flag为true,线程A 就会先得到/持有 o1对象锁,然后尝试去获取o2对象锁//(2)如果flag为true,线程A 就会先得到/持有 o1对象锁,然后尝试去获取o2对象锁if (flag) {synchronized (o1) {System.out.println(Thread.currentThread().getName() + "进入1");synchronized (o2) {System.out.println(Thread.currentThread().getName() + "进入2");}}} else {synchronized (o2) {System.out.println(Thread.currentThread().getName() + "进入3");synchronized (o1) {System.out.println(Thread.currentThread().getName() + "进入4");}}}}
}
wait():当前线程暂停,并释放锁;
sleep()、yield():不会释放锁;