0
点赞
收藏
分享

微信扫一扫

JAVA多线程笔记

phpworkerman 2022-01-17 阅读 67

JAVA多线程

线程创建

1.Thread类

  1. 自定义线程类继承Thread类

  2. 重写run()方法,编写线程执行体

  3. 创建线程对象,调用start()方法启动线程

//创建线程方式一:继承Thread类 重写run()方法,调用start开启线程
public class TestThread1 extends Thread{
   @Override
   public void run() {
       //run方法线程体
       for (int i = 0; i < 20; i++) {
           System.out.println("我在看代码"+i);
      }
  }
   //main线程,主线程
   public static void main(String[] args) {
       
       //创建一个线程对象
       TestThread1 testThread1 = new TestThread1();
       //调用start()方法开启线程(交替执行)
       testThread1.start();
       //调用run()方法先执行run()再执行主方法
       //testThread1.run();
       for (int i = 0; i < 20; i++) {
           System.out.println("我在执行多线程"+i);
      }

  }
}

/*注意!线程开启不一定立即执行,由CPU调度执行*/

2.Runnable接口(实现Runnable接口)推荐

  1. 定义MyRunnable类实现Runnable接口

  2. 实现run()方法,编写线程执行体

  3. 创建线程对象,调用start()方法启动线程

//创建线程方式2:实现runnable接口,重写run方法,执行线程需要丢入runnable类接口实现类,调用start方法
public class TestThread3 implements Runnable{
   @Override
   public void run() {
       //run方法线程体
       for (int i = 0; i < 20; i++) {
           System.out.println("我在看代码"+i);
      }
  }

   public static void main(String[] args) {
       //创建runnable接口的实现类对象
       TestThread3 testThread3 = new TestThread3();
       //创建线程对象,通过线程对象来开启我们的线程
       Thread thread = new Thread(testThread3);

       thread.start();

       //简写 newThread(testThread3).start();

       for (int i = 0; i < 20; i++) {
           System.out.println("我在执行多线程"+i);
      }

  }
}

3.Callable接口(实现Callable接口)

  1. 实现Callable接口,需要返回值类型

  2. 重写call方法,需要抛出异常

  3. 创建目标对象

  4. 创建执行服务

ExecutorService ser = Executors.newFixedThreadPool(1);
  1. 提交执行

Future<Boolean>result1 = ser.submit(t1);
  1. 获取结果

boolean r1 = result.get()
  1. 关闭服务

ser.shutdownNow();

/*图片下载案例 callable方法实现*/
​
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

/**
* TODO
*
* @author wlj
* @version 1.0
* @Description
* @date 2022/1/15 16:39
*/


/*
callable的好处
可以抛出异常
具有返回值
*/


//线程创建方式三:实现callable接口
public class TestCallable implements Callable<Boolean> {
   private String url;//网络图片地址
   private String name;//保存的文件名

   public TestCallable(String url, String name) {
       this.url = url;
       this.name = name;
  }


   @Override
   public Boolean call() {
       WebDownloader webDownloader = new WebDownloader();
       webDownloader.downloader(url, name);
       System.out.println("下载了文件名为:" + name);
       return true;
  }

   public static void main(String[] args) throws ExecutionException, InterruptedException {


       TestCallable testThread1 = new TestCallable("https://webstatic.mihoyo.com/upload/puzzle/2021/12/22/1a4f9ac397162af7b11616ea7acb5115_4472408160447119381.png", "1.jpg");
       TestCallable testThread2 = new TestCallable("https://webstatic.mihoyo.com/upload/puzzle/2021/12/22/1a4f9ac397162af7b11616ea7acb5115_4472408160447119381.png", "2.jpg");
       TestCallable testThread3 = new TestCallable("https://webstatic.mihoyo.com/upload/puzzle/2021/12/22/1a4f9ac397162af7b11616ea7acb5115_4472408160447119381.png", "3.jpg");

/*======================================================================*/
       //创建执行服务 线程池
       ExecutorService ser = Executors.newFixedThreadPool(3);

       //提交执行
       Future<Boolean> r1 = ser.submit(testThread1);
       Future<Boolean> r2 = ser.submit(testThread2);
       Future<Boolean> r3 = ser.submit(testThread3);

       //获取结果
       boolean rs1 = r1.get();
       boolean rs2 = r2.get();
       boolean rs3 = r3.get();

       //打印返回结果
       System.out.println(rs1);
       System.out.println(rs2);
       System.out.println(rs3);

       //关闭服务
       ser.shutdownNow();
/*====================================================================*/
  }
}


//下载器
class WebDownloader {
   //下载方法
   public void downloader(String url, String name) {
       try {
           FileUtils.copyURLToFile(new URL(url), new File(name));
      } catch (IOException e) {
           e.printStackTrace();
           System.out.println("IO异常,downloader方法出现问题");
      }
  }
}

线程休眠

  1. sleep(时间)指定当前线程阻塞的毫秒数

  2. sleep存在异常InterruptedException

  3. sleep时间达到后线程进入就绪状态

  4. sleep可以模拟网络延时,倒计时

  5. 每一个对象都有一个锁,sleep不会释放锁

//模拟倒计时
public class TestSleep2 {
   public static void main(String[] args) {
//       try {
//           tenDown();
//       } catch (InterruptedException e) {
//           e.printStackTrace();
//       }

       //打印当前时间
       Date startTime = new Date(System.currentTimeMillis());//获取当前系统时间
       while(true){
           try {
               Thread.sleep(1000);
               System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
               startTime = new Date(System.currentTimeMillis());//更新当前时间
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
      }
  }

   public static void tenDown() throws InterruptedException{
       int num = 10;
       while (true) {
           Thread.sleep(1000);
           System.out.println(num--);
           if(num<=0){
               break;
          }
      }
  }
}

线程关闭

  1. 不推荐使用JDK提供的stop(),destory()方法【已废弃】

  2. 推荐线程自己停止下来

  3. 建议使用一个标志位进行终止变量,当flag = false,则终止线程运行

//测试stop
//1.建议线程正常停止--->利用次数,不建议死循环
//2.建议使用标志位--->摄制一个标志位
//3.不要使用stop或者destroy等过时或者JDK不建议使用的方法
public class TestStop implements Runnable{

//1.设置一个标识位
private boolean flag = true;

@Override
public void run() {

int i = 0;
while(flag){
System.out.println("run...Thread"+i++);
}
}

//2.设置一个公开的方法停止线程,转换标志位

public void stop(){
this.flag = false;
}

public static void main(String[] args) {
TestStop testStop = new TestStop();

new Thread(testStop).start();

for (int i = 0; i < 1000; i++) {
System.out.println("main"+i);
if(i == 900){
//调用自己写的stop方法切换标志位,让线程停止
testStop.stop();
}
}
}
}

线程礼让

  1. 礼让线程,让当前正在执行的线程暂停,但不阻塞

  2. 将线程从运行状态转为就绪状态

  3. 让CPU重新调度,礼让不一定成功

//测试礼让线程
//礼让不一定成功,看CPU心情
public class TestYield {

public static void main(String[] args) {
MyYield myYield = new MyYield();

new Thread(myYield,"a").start();
new Thread(myYield,"b").start();
}

}

class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程开始执行");
Thread.yield();//礼让
System.out.println(Thread.currentThread().getName()+"线程停止执行");
}
}

线程强制执行

//测试Join方法, 想象为插队
public class TestJoin implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("vip线程来了"+i);
}
}

public static void main(String[] args) throws InterruptedException{

//启动我们的线程
TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();

//主线程

for (int i = 0; i < 500; i++) {
if(i == 200){
thread.join();//插队
}
System.out.println("main"+i);
}
}
}

线程状态观察

public class TestState {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("///");
});


//观察状态
Thread.State state = thread.getState();
System.out.println(state); //NEW

//观察启动后
thread.start();//启动线程
state = thread.getState();
System.out.println(state);//Run

while(state != Thread.State.TERMINATED){//只要线程不终止 就一直输出状态
Thread.sleep(100);
state = thread.getState();//更新线程状态
System.out.println(state);//打印线程状态
}
}
}

线程优先级

线程的优先级用数字表示,范围从1~10

  1. Thread.MIN_PRIORITY = 1;

  2. Thread.MAX_PRIORITY = 10;

  3. Thread.NORM_PRIORITY = 5;

使用以下方式改变或获取优先级

  1. getPriority()

  2. setPriority(int xxx)

public class TestPriority {

   public static void main(String[] args) {
       //主线程默认优先级
       System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());

       MyPriority myPriority = new MyPriority();
       Thread t1 = new Thread(myPriority);
       Thread t2 = new Thread(myPriority);
       Thread t3 = new Thread(myPriority);
       Thread t4 = new Thread(myPriority);
       Thread t5 = new Thread(myPriority);
       Thread t6 = new Thread(myPriority);

       //先设置优先级,在启动
       t1.start();
       t2.setPriority(1);
       t2.start();
       t3.setPriority(4);
       t3.start();
       t4.setPriority(Thread.MAX_PRIORITY);
       t4.start();

  }
}

class MyPriority implements Runnable{

   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
  }
}

守护线程

  1. 线程分为用户线程和守护线程

  2. 虚拟机必须确保用户线程执行完毕

  3. 虚拟机不用等待守护线程执行完毕

  4. 如:后台记录操作日志,监控内存,垃圾回收等待

//测试守护线程
public class TestDaemon {
   public static void main(String[] args) {
       God god = new God();
       You you = new You();

       Thread thread = new Thread(god);
       thread.setDaemon(true);//默认是false表示是用户线程,正常的线程都是用户线程
       thread.start();//上帝守护线程启动

       new Thread(you).start();//你 用户线程启动

  }
}

//上帝

class God implements  Runnable{
   @Override
   public void run() {
       while(true){
           System.out.println("上帝保佑你");
      }
  }
}

//你
class You implements Runnable{
   @Override
   public void run() {
       for (int i = 0; i < 36500; i++) {
           System.out.println("你一生都开心地活着");
      }
       System.out.println("-====goodbye! world!====-");
  }
}
举报

相关推荐

0 条评论