目录
3:含有join,sleep,wait等需要interrupt()打断
3:线程阻塞(sleep,join,wait,notify,yield)
含有join,sleep,wait等需要interrupt()打断
1:线程的生命周期
-
新建(通过构造)
-
就绪(通过start()方法)
-
执行(通过资源调度,获取资源)
-
阻塞
-
死亡
1:线程的终止
1:通过给定属性,然后通过控制属性值来破坏继续执行的条件
第一种,通过给定属性,然后通过控制属性值来破坏继续执行的条件
线程代码如下:
package cn.sz.gl.test03;
public class MyRun implements Runnable {
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag) {
System.out.println("执行线程_" + i);
i++;
}
}
public void changeFlag() {
flag = false;
}
}
测试代码如下:
package cn.sz.gl.test03;
public class Test {
public static void main(String[] args) {
MyRun mr = new MyRun();
new Thread(mr).start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mr.changeFlag();
}
}
2:interrupt()进行打断线程
第二种,对于正在执行的线程,interrupt()是给线程设置中断标志;interrupted()是检测中断并清除中断状态;isInterrupted()只检测中断。还有重要的⼀点就是interrupted()作⽤于当前线程,interrupt()和isInterrupted()作⽤于此线程,即代码中调⽤此⽅法的线程
线程代码如下:
package cn.sz.gl.test03;
public class MyRun2 implements Runnable {
@Override
public void run() {
int i = 0;
while(!Thread.interrupted()){
System.out.println("我的线程_"+i);
i++;
}
}
}
测试代码如下:
package cn.sz.gl.test03;
public class Test2 {
public static void main(String[] args) {
//System.out.println(Thread.interrupted());//默认为false
MyRun2 mr = new MyRun2();
Thread th = new Thread(mr);
th.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
th.interrupt();
}
}
3:含有join,sleep,wait等需要interrupt()打断
第三种,如果线程因为执行join(),sleep()或是wait()而进入了阻塞状态,此时要想停止它,可以让它调用interrupt(),程序会抛出InterruptedException异常而被catch()子句捕获,进行处理
线程代码如下:
package cn.sz.gl.test03;
public class MyRun3 implements Runnable {
@Override
public void run() {
int i = 0;
while(true){
System.out.println("线程_"+i);
i++;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
break;
}
}
}
}
测试代码如下:
package cn.sz.gl.test03;
public class Test3 {
public static void main(String[] args) {
MyRun3 mr = new MyRun3();
Thread th = new Thread(mr);
th.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//当调用interrupt方法时,可以改变interrupted的值
//当th线程中有处理InterruptedException异常的时候,如果该线程调用了interrupt方法,那么该线程会抛出InterruptedException异常
th.interrupt();
}
}
2:线程的同步(synchronized)
处理多线程的问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象,这个时候我们就需要线程同步,线程同步其实就是一种等待机制,多个需要同时访问该对象的线程进入这个对象的等待池中,形成队列,等待前面线程使用完成,下一个线程再使用
在Java语言中,引入对象互斥锁的概念,保证共享数据操作的完整性;
每个对象都对应于一个可称为"互斥锁"的标记,这个标记保证在任一时刻,只能有一个线程访问对象;
用关键字synchronized给对象加互斥锁.
1:同步代码块
synchronized放在对象前面限制一段代码的执行,其语法如下:
Object obj = new Object();
...
synchronized(this){//this被加锁,任何其他要锁this的方法和代码块被阻塞.
需要同步的代码;
}
...
synchronized(obj){//obj被加锁,任何其他要锁obj的代码块被阻塞.
需要同步的代码;
}
2:同步方法
同步非静态方法:synchronized放在方法声明中,表示整个方法为同步方法,锁定this对象,如果有一个线程进入了该方法,其他线程要想使用当前this对象的任何同步方法,都必须等待前一个线程执行完该同步方法之后
如下:
public synchronized void method1(){
…
}
public synchronized void method2(){
…
}
public synchronized void method3(){
…
}
同步static方法: synchronized放在static方法声明中,表示锁定该类的class对象(xxx.class,是Class类型的,是描述一个类的信息的对象)
如果有一个线程进入了该方法,其他线程要想使用当前类中的任何同步静态方法,都必须等待前一个线程执行完该同步方法之后;其他非同步方法及非静态的同步方法的执行不受影响
如下:
public synchronized static void method1(){
…
}
public synchronized static void method2(){
…
}
注意:
当前线程调用本同步方法时,其他线程是不允许调用本对象中其他同步方法
当前线程在调用本同步静态方法时,其他线程是不能够调用本类中的其他同步静态方法的,但是可以调用本类中的其他非同步方法或者非静态同步方法
对于同步静态方法,此时锁定的是对应的类型(类名.class),所有属于该类型的对象,都在其锁定范围内,此时可以实现方法的同步调用
线程同步的引发的问题:
-
一个线程持有锁会导致其他所有需要该锁的线程阻塞
-
在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题
-
线程同步可能会造成死锁
3:线程阻塞(sleep,join,wait,notify,yield)
-
同步阻塞
-
调用sleep(),join()方法的时候,sleep()转为休眠,时间到自动唤醒
-
wait(),notify()方法配套,转为等待,同时释放资源,通过notify()方法唤醒
-
yield(),释放资源,与其他线程重新抢占资源,抢到就执行
-
suspend()和resume(),由jdk1.0提供,jdk1.2之后就被放弃了,它也是让线程暂停,但是它不释放资源,导致死锁出现
1:join()使用案例
package ThreadPractise;
import java.util.ArrayList;
public class Demo implements Runnable{
public static void parseLog(String log) throws Exception {
System.out.println(log+":"+Thread.currentThread().getName());
Thread.sleep(1000);
}
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
ArrayList<Thread> threads = new ArrayList<>();
Demo demo = new Demo();
Thread t1 = new Thread(demo,"s1");
Thread t2 = new Thread(demo,"s2");
Thread t3 = new Thread(demo,"s3");
Thread t4 = new Thread(demo,"s4");
threads.add(t1);
threads.add(t2);
threads.add(t3);
threads.add(t4);
t1.start();
t2.start();
t3.start();
t4.start();
for (Thread thread :
threads) {
thread.join();
}
long end = System.currentTimeMillis();
System.out.println((end-start)/1000);
}
@Override
public void run() {
for (int i = 0; i < 4; i++) {
try {
parseLog(">>>"+(i+1));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
4:线程死锁(max)
死锁产生的必要条件:
1> 互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
2> 不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
3> 请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占用。
4> 循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路
在我们的项目中,我们不希望看到死锁的发生,为了避免,以上四个条件,破坏其中任意一个,死锁就结束了
注意:过多的同步会导致死锁
死锁示例如下:
package cn.sz.gl.no5;
public class MyRun implements Runnable {
private static Object a = new Object();
private static Object b = new Object();
private boolean flag = true;
public void changeFlag(){
flag = false;
}
@Override
public void run() {
if(flag){
synchronized (a) {
System.out.println(Thread.currentThread().getName()+"锁定了资源a");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b) {
System.out.println(Thread.currentThread().getName()+"锁定资源b");
}
}
}else{
synchronized (b) {
System.out.println(Thread.currentThread().getName()+"锁定了资源b");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a) {
System.out.println(Thread.currentThread().getName()+"锁定资源a");
}
}
}
}
}
测试如下:
package cn.sz.gl.no5;
public class Test {
public static void main(String[] args) throws InterruptedException {
MyRun mra = new MyRun();
new Thread(mra,"线程1").start();
Thread.sleep(10);
mra.changeFlag();
new Thread(mra,"线程2").start();
}
}
2:多线程加载方式
3:总结
线程生命周期图:
五大状态:创建状态、就绪状态、运行状态、阻塞状态、死亡状态
含有join,sleep,wait等需要interrupt()打断
4、建议采纳
如有建议或者错误请私信我进行修改,感谢!!!