多线程并发

1.创建和运行线程

方法一:直接使用 Thread

// 构造方法的参数是给线程指定名字,推荐
Thread t1 = new Thread("t1") {
 @Override
 // run 方法内实现了要执行的任务
 public void run() {
 log.debug("hello");
 }
};
t1.start();

方法二,使用 Runnable 配合 Thread
把【线程】和【任务】(要执行的代码)分开
Thread 代表线程
Runnable 可运行的任务(线程要执行的代码)
如果runnable里面有run方法,即优先调用runnable里面的run方法,否则调用Thread里面的run方法。

Runnable runnable = new Runnable() {
 public void run(){
 // 要执行的任务
 }
};
// 创建线程对象
Thread t = new Thread( runnable );
// 启动线程
t.start();

方法三,FutureTask 配合 Thread
FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况

// 创建任务对象
FutureTask<Integer> task3 = new FutureTask<>(() -> {
 log.debug("hello");
 return 100;
});
// 参数1 是任务对象; 参数2 是线程名字,推荐
new Thread(task3, "t3").start();
// 主线程阻塞,同步等待 task 执行完毕的结果
Integer result = task3.get();
log.debug("结果是:{}", result);

2. 查看进程线程的方法

windows
任务管理器可以查看进程和线程数,也可以用来杀死进程
tasklist 查看进程
taskkill 杀死进程
linux
ps -fe 查看所有进程
ps -fT -p 查看某个进程(PID)的所有线程
kill 杀死进程
top 按大写 H 切换是否显示线程
top -H -p 查看某个进程(PID)的所有线程
Java
jps 命令查看所有 Java 进程
jstack 查看某个 Java 进程(PID)的所有线程状态
jconsole 来查看某个 Java 进程中线程的运行情况(图形界面)

在这里插入图片描述

3.run和start区别

直接调用 run 是在主线程【main】中执行了 run,没有启动新的线程
使用 start 是启动新的线程,通过新的线程间接执行 run 中的代码

4.sleep 与 yield sleep

Thread.sleep在哪里他就是让哪个线程睡眠

  1. 调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)
  2. 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException
  3. 睡眠结束后的线程未必会立刻得到执行
  4. 建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性
    yield
  5. **调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,**然后调度执行其它线程
  6. 具体的实现依赖于操作系统的任务调度器
    让出CPU的使用权(礼让)

5.wait()方法和join()方法

java中的wait()方法

wait()方法的作用是让当前线程进入等待状态,wait()会与notify()和notifyAll()方法一起使用。

notify()和notifyAll()方法的作用是唤醒等待中的线程,notify()方法:唤醒单个线程,notifyAll()方法:唤醒所有线程。

java中的join()方法

join()方法是等待这个线程结束,完成其执行。它的主要起同步作用,使线程之间的执行从“并行”变成“串行”。

也就是说,当我们在线程A中调用了线程B的join()方法时,线程执行过程发生改变:线程A,必须等待线程B执行完毕后,才可以继续执行下去。

wait()方法和join()方法的相似处

1、wait()和join()方法都用于暂停Java中的当前线程,进入等待状态。

2、在Java中都可以调用interrupt()方法中断wait()和join()的线程状态。

3、wait()和join()都是非静态方法。

4、wait()和join()都在Java中重载。wait()和join()没有超时,但接受超时参数。

尽管wait()方法和join()方法有相似之处,但wait()方法和join()方法还是存在差异的。

wait()方法和join()方法之间的区别

1、存在不同的java包中(最明显的区别)

wait()方法需要在java.lang.Object类中声明;而,join()方法是在java.lang.Thread类中声明。

2、使用目的不同

wait()方法用于线程间通信;而join()方法用于在多个线程之间添加排序,第二个线程需要在第一个线程执行完成后才能开始执行。

3、唤醒线程方面的区别

我们可以通过使用notify()和notifyAll()方法启动一个通过wait()方法进入等待状态的线程。但是我们不能打破join()方法所施加的等待,除非或者中断调用了连接的线程已执行完了。

4、同步上下文(最重要的区别)
wait()方法必须从同步(synchronized)的上下文调用,即同步块或方法,否则会抛出IllegalMonitorStateException异常。

6.模式之两阶段终止

public class Test6 {

    public static void main(String[] args) throws InterruptedException {
        TwoPhaseTerminnation tpt = new TwoPhaseTerminnation();
        tpt.start();
        //tpt.start();
     //   tpt.start();
       Thread.sleep(3500);
       tpt.stop();//主线程睡眠3500ms后继续往下执行

    }
    
}
@Slf4j(topic = "c.Two")
class  TwoPhaseTerminnation{
        private Thread monitor;


        //启动监控线程
      public  void start(){
          monitor=new Thread(()->{
              while (true){
                  Thread current=Thread.currentThread();
                  if(current.isInterrupted()){
                      log.debug("处理问题");
                      break;
                  }
                  try {
                      Thread.sleep(1000);//每隔1000秒发消息
                      log.debug("执行监控记录");
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                      current.interrupt();
                  }
              }
          });
          monitor.start();

      }
      //停止监控线程
      public  void  stop(){
          monitor.interrupt();
      }

  }

7.synchronized

为了避免临界区的竞态条件发生,有多种手段可以达到目的。
阻塞式的解决方案:synchronized,Lock
非阻塞式的解决方案:原子变量
面向对象改进:把需要保护的共享变量放入一个类

class Room {
 int value = 0;
 public void increment() {
 synchronized (this) {
 value++;
 }
 }
 public void decrement() {
 synchronized (this) {
 value--;
 }
 }
 public int get() {
 synchronized (this) {
 return value;
 }
 }
}
@Slf4j
public class Test1 {
 
 public static void main(String[] args) throws InterruptedException {
 Room room = new Room();
 Thread t1 = new Thread(() -> {
 for (int j = 0; j < 5000; j++) {
 room.increment();
 }
 }, "t1");
 Thread t2 = new Thread(() -> {
 for (int j = 0; j < 5000; j++) {
 room.decrement();
 }
 }, "t2");
 t1.start();
 t2.start();
 t1.join();
 t2.join();
 log.debug("count: {}" , room.get());
 }
}
class Test{
 public synchronized void test() {
 
 }
}
等价于
class Test{
 public void test() {
 synchronized(this) {
 
 }
 }
}
class Test{
 public synchronized static void test() {
 }
}
等价于
class Test{
 public static void test() {
 synchronized(Test.class) {
 
 }
 }
}

原理之 wait / notify

基于对象去实现
API 介绍
obj.wait() 让进入 object 监视器的线程到 waitSet 等待
obj.notify() 在 object 上正在 waitSet 等待的线程中挑一个唤醒
obj.notifyAll() 让 object 上正在 waitSet 等待的线程全部唤醒

它们都是线程之间进行协作的手段,都属于 Object 对象的方法。必须获得此对象的锁,才能调用这几个方法

final static Object obj = new Object();
public static void main(String[] args) {
 new Thread(() -> {
		 synchronized (obj) {
		     log.debug("执行....");
		 try {
		     obj.wait(); // 让线程在obj上一直等待下去
		 } catch (InterruptedException e) {
		     e.printStackTrace();
		 }
		   log.debug("其它代码....");
		 }
		 }).start();
 new Thread(() -> {
	    synchronized (obj) {
	        log.debug("执行....");
	    try {
	      obj.wait(); // 让线程在obj上一直等待下去
	     } catch (InterruptedException e) {
	           e.printStackTrace();
	 }
	              log.debug("其它代码....");
	 }
	 }).start();
 // 主线程两秒后执行
 sleep(2);
 log.debug("唤醒 obj 上其它线程");
 synchronized (obj) {
 obj.notify(); // 唤醒obj上一个线程
 // obj.notifyAll(); // 唤醒obj上所有等待线程
 }
}
notify 的一种结果
20:00:53.096 [Thread-0] c.TestWaitNotify - 执行.... 
20:00:53.099 [Thread-1] c.TestWaitNotify - 执行.... 
20:00:55.096 [main] c.TestWaitNotify - 唤醒 obj 上其它线程
20:00:55.096 [Thread-0] c.TestWaitNotify - 其它代码.... 
notifyAll 的结果
19:58:15.457 [Thread-0] c.TestWaitNotify - 执行.... 
19:58:15.460 [Thread-1] c.TestWaitNotify - 执行.... 
19:58:17.456 [main] c.TestWaitNotify - 唤醒 obj 上其它线程
19:58:17.456 [Thread-1] c.TestWaitNotify - 其它代码.... 
19:58:17.456 [Thread-0] c.TestWaitNotify - 其它代码.... 

wait() 方法会释放对象的锁,进入 WaitSet 等待区,从而让其他线程就机会获取对象的锁。无限制等待,直到
notify 为止
wait(long n) 有时限的等待, 到 n 毫秒后结束等待,或是被 notify
sleep(long n) 和 wait(long n) 的区别

  1. sleep 是 Thread 方法,而 wait 是 Object 的方法
  2. sleep 不需要强制和 synchronized 配合使用,但 wait 需要
    和 synchronized 一起用
  3. sleep 在睡眠的同时,不会释放对象锁的 其他线程获得不了锁,但 wait 在等待的时候
    会释放对象锁
  4. 它们状态 TIMED_WAITING

wait notify 的正确姿势

synchronized(lock) {
 while(条件不成立) {
 lock.wait();
 }
 // 干活
}
//另一个线程
synchronized(lock) {
 lock.notifyAll();
}
package lock;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Test3 {
    static  final  Object room=new Object();
    static  boolean hasCigarette=false;
    static  boolean hasTakeout=false;
    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            synchronized (room) {
                log.debug("有烟没?[{}]", hasCigarette);
               while (!hasCigarette) {
                    log.debug("没烟,先歇会!");
                    try {
                      //  Thread.sleep(2000);
                        room.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.debug("有烟没?[{}]", hasCigarette);
                if (hasCigarette) {
                    log.debug("可以开始干活了");
                }
            }
        }, "小南").start();
        new Thread(() -> {
            synchronized (room) {
             //   Thread thread = Thread.currentThread();
                log.debug("外卖送到没?[{}]", hasTakeout);
                while (!hasTakeout) {
                    log.debug("没外卖,先歇会!");
                    try {
                        room.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.debug("外卖送到没?[{}]", hasTakeout);
                if (hasTakeout) {
                    log.debug("可以开始干活了");
                } else {
                    log.debug("没干成活...");
                }
            }
        }, "小女").start();
        Thread.sleep(1000);
        new Thread(() -> {
            synchronized (room) {
                hasTakeout = true;
                log.debug("外卖到了噢!");
                room.notifyAll();
            }
        }, "送外卖的").start();
    }
}

模式之保护性暂停

package lock;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.List;

@Slf4j
public class Test4 {
    public static void main(String[] args) {
        GuardedObject guardedObject = new GuardedObject();

        new Thread(() -> {
            //等待结果
            log.debug("等待结果");
//            List<String> list= (List<String>) guardedObject.get(2000);
//            log.debug("结果大小:{}",list);
            Object response= guardedObject.get(2000);
            log.debug("结果大小:{}",response);

        },"t1").start();
//等待时间<下载时间  返回空
// 等待时间》=下载进程休眠时间  返回内容
// 等待时间过程中有其他进程误入来叫醒,继续按原计划等够时间再返回结果不是重头开始算。
//        new Thread(()->{
//            log.debug("begin");
//            try {
//                Thread.sleep(3000);
//                guardedObject.comlete(new Object());
//            //    guardedObject.comlete(null);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        },"t2").start();

        new Thread(()->{
            log.debug("执行下载");
            try {
                List<String> list = Downloader.download();
                guardedObject.comlete(list);
            } catch (IOException e) {
                e.printStackTrace();
            }
        },"t2").start();

    }
}
class  GuardedObject{
    //结果
    private  Object response;
    public  Object get(long timeout) {
        synchronized (this){
            //开始时间
            long begin = System.currentTimeMillis();
            long passedTime=0;
            while (response==null){
                if(passedTime>=timeout){
                    break;
                }
                try {
                    this.wait(timeout-passedTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                passedTime=System.currentTimeMillis()-begin;
            }
            return  response;
        }
    }

    //产生结果
    public  void comlete(Object response){
        synchronized (this){
            //给结果成员变量赋值
            this.response=response;
            this.notifyAll();
        }
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值