JAVA多线程(一)------线程创建、运行状态和终止

     将最近学习的JAVA多线程知识在这里进行总结和分享,以便以后查看。所有内容仅供参看,有不正确的地方欢迎指出。

一.基本概念

1.常见术语

  • 多线程:指的是这个程序(一个进程)运行时产生了不止一个线程
  • 并行:多个cpu实例或者多台机器同时执行一段处理逻辑
  • 并发:通过cpu调度算法,不断切换时间片,执行线程.当一个线程处在运行状态时,其它线程处于挂起状态
  • 线程安全:在并发情况下,一段逻辑经过多线程使用,线程的调度顺序不影响最终结果。
  • 同步:使线程共享的资源始终保持一致和准确。

2,应该场景(多个线程调度可以优化系统性能

  •     网络请求分发的场景
  •     文件导入
  •     短信发送场景

二、Java中线程六种状态

                              

  •     wait():持有对象锁的线程A准备释放对象锁权限,释放cpu资源并进入等待状态
  •     notify(): 线程A的synchronized 代码执行结束并且释放锁之后,线程X直接获得对象锁权限,其他竞争线程继续等待(线程x同步完毕释放对象锁,其他线程仍然等待,直至有新的notify,notifyAll被调用)
  •     notifyAll(): 会唤醒所有竞争同一对象锁的所有线程,线程A的synchronized 代码执行结束并且释放锁之后,所有被唤醒的线程都有可能获得对象锁权限。

          注:wait();     notify():;     notifyAll(): 三个方法都必须在synchronized 同步关键字所限定的作用域中调用

  •      yield():让出时间片,重新调度。当前线程调用此方法,告诉cpu吧运行机会交给线程池中拥有相同优先级的线程。不保证一定能达到让位的目的,让步的线程可能再次被调度程度选中。yield()不会导致阻塞。和sleep(o)效果上一样
  •       join():本质是wait/ notify,让线程的执行结果可见。 当前线程里调用其它线程的join方法,当前线程阻塞 ,直到线程执行完毕或者到达设定的时间
public class JoinDemo {
    private static int i=10;
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            i=30;
            try {Thread.sleep(3000); } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t.start();
        /两个线程仍是并行,可以继续其他操作
        t.join(); // //t线程中的执行结果对于main线程可见.
        //延迟3秒后输出i:30
        System.out.println("i:"+i);
    }
}

2. 线程状态查看

1)在控制台 执行 jps 命令获取线程Id

2)“ jstack 线程Id" 查看线程状态

              

三、线程的死锁

       一组互相竞争资源的线程因互相等待,导致永久阻塞的现象

    1.死锁发生的条件

          1)互斥,共享资源 X Y 只能被一个线程占用;

          2)占有且等待,线程 T1 已经取得共享资源 X,在等待共享资源 Y 的时候,不释放共享资源 X

          3)不可抢占,其他线程不能强行抢占线程 T1 占有的资源;

          4)循环等待,线程 T1 等待线程 T2 占有的资源,线程 T2 等待线程 T1 占有的资源,就是循环等待。

     2.如何解决死锁问题

           按照前面说的四个死锁的发生条件,互斥这个条件我们没有办法破坏,因为我们用锁为的就是互斥,其他三个条件,我们只需要破坏其中一个,就可以避免死锁的产生。

         1)对于占用且等待这个条件,我们可以一次性申请所有的资源,这样就不存在等待了。

          2)对于不可抢占这个条件,占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动  释放它占有的资源,这样不可抢占这个条件就破坏掉了。

          3)对于循环等待这个条件,可以靠按序申请资源来预防。所谓按序申请,是指资源是有线性顺序的,申请的时候可以先申请资源序号小的,再申请资源序号大的,这样线性化后自然就不存在循环  了。

四、线程的创建

1.实现Runable接口实现run()方法

public class MyThread extends OtherClass implements Runnable {
public void run() {
System.out.println("MyThread.run()");
}
}

2.继承Thread类重写run方法。本质上是实现了 Runnable 接口的一个实例,通过 Thread类的 start() 实例方法。

public class MyThread extends Thread {
 public void run() { 
System.out.println("MyThread.run()"); 
} 
}
 MyThread myThread1 = new MyThread();
 MyThread myThread2 = new MyThread();
 myThread1.start();
 myThread2.start();

                

3.实现Callable 接口实现call()抽象方法,通过 FutureTask 包装器创建带返回值的线程(底层是实现了runnable接口和future接口)

public class Test  implements Callable<String> {

   public static void main(String[] args) throws ExecutionException, InterruptedException {
            Test callableDemo=new Test();
            FutureTask<Integer> result = new FutureTask(callableDemo);
            new Thread(result).start();
           System.out.println(result.get());
        }
        @Override
        public String call() throws Exception {
            int a=1;
            int b=2;
            System.out.println(a+b);
            return "执行结果:"+(a+b);
        }
}

4.线程池:提供了一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁额外开销,提高了响应的速度。

三.线程终止

1.stop()//强制终止,不建议使用,会破坏未执行完的线程

2.interrupt()//设置一个中断标志,通知线程自己处理,并终止。(处理权在线程,不在外部调用,处于阻塞的线程,不一定会终止)

   1) 作用:

        a.设置一个共享变量的值 true;

        b.唤醒处于阻塞状态下的线程。

  案例1:线程为非阻塞状态

public class InterruptDemo implements Runnable{
    private int i=1;
    @Override
    public void run() {
// Thread.currentThread().isInterrupted()=false;(表示一个中断的标记  interrupted=fasle)
        while(!Thread.currentThread().isInterrupted()){
            System.out.println("Test:"+i++);
        }
    }
    public static void main(String[] args) {
        Thread thread=new Thread(new InterruptDemo());
        thread.start();
        thread.interrupt(); //设置 interrupted=true;
    }
}

案例2:线程为阻塞状态

public class InterruptDemo02 implements Runnable{
    @Override
    public void run() {
        while(!Thread.currentThread().isInterrupted()){ //false
            try {
                TimeUnit.SECONDS.sleep(200);
            } catch (InterruptedException e) {
                //InterruptedException异常会对isInterrupted进行复位为false (//Thread.interrupted() 方法也可以进行复位)
                e.printStackTrace();
                //抛出异常后线程不会结束
                // 线程自己觉得进行操作。比如处理,比如再次中断
                Thread.currentThread().interrupt(); //再次中断
                //抛出异常。。
            }
        }
        System.out.println("processor End");
    }
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(new InterruptDemo02());
        t1.start();
        Thread.sleep(1000);
        t1.interrupt(); //有作用 true
        
    }
}

流程:t1 运行 isInterrupted =false --->主线程睡1s ----->t1线程进入while循环,睡200s -----> 主线程时间结束执行t1.interrupt()---> isInterrupted =true----->t1线程被唤醒-----> 抛出InterruptedException 中断异常, isInterrupted被复位为false---->执行Thread.currentThread().interrupt()再次中断  -----> isInterrupted =true--->输出processor End

        2)JVM调用的操作系统源码

  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值