多线程基础
-
线程简介
-
任务
-
进程(Process)
-
一个进程可以有多个线程
-
-
线程(Thread)
-
多线程
-
核心
-
线程就是独立的执行路径
-
在程序运行时,即使没有自己创建的线程,后台也会有多个线程,
-
main()称之为主线程,为系统的入口,用于执行整个程序
-
在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能认为的干预的
-
对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制
-
线程会带来额外的开销,如cpu调度时间,并发控制开销
-
每个线程在自己的工作仍存交互,仍存控制不当造成数据不一致
-
-
-
线程实现(重点)
-
三种创建方式
-
继承Thread(重点)实际上Thread也实现了Runnable接口都得重写run()方法
-
线程和mian同时进行(两线程同时进行)
//创建线程方式一:继承Thread类,重写run()方法,调用start开启线程 //总结:注意,线程开启不一定立即执行,由CPU调度 public class TestThread1 extends Thread{ @Override public void run() { //run方法线程体 for (int i = 0; i < 20; i++) { System.out.println("我在看代码"+i); } } public static void main(String[] args) { //main()线程,主方法 //创建一个线程 TestThread1 testThread1 = new TestThread1(); //线程开始start()方法开启线程 testThread1.start(); for (int i = 0; i < 20; i++) { System.out.println("我在学习线程"+i); } } }
-
-
实现Runnable接口(重点)
public class TestRunnable1 implements Runnable{ @Override public void run() { //run方法线程体 for (int i = 0; i < 20; i++) { System.out.println("我在看代码"+i); } } public static void main(String[] args) { //main()线程,主方法 //创建一个线程 TestRunnable1 testRunnable1=new TestRunnable1(); // Thread thread = new Thread(testRunnable1); // thread.start(); //线程开始start()方法开启线程 new Thread(testRunnable1).start(); for (int i = 0; i < 20; i++) { System.out.println("我在学习线程"+i); } } }
-
小结:
-
继承Thread类
-
子类继承Thread类具备多线程能力
-
启动线程:子类对象.start()
-
不建议使用:避免OOP单继承局限性
-
-
实现Runnable接口
-
实现接口Runnable具备多线程能力
-
启动线程:传入目标对象+Thread对象.start()。
-
推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
public class TestRunnable2 implements Runnable{ private int sum=10; @Override public void run() { while (true){ if (sum<=0){ break; } try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+ "---->拿到了第"+sum--+"票"); } } public static void main(String[] args) { TestRunnable2 testRunnable2=new TestRunnable2(); new Thread(testRunnable2,"小明").start(); new Thread(testRunnable2,"黄牛党").start(); new Thread(testRunnable2,"小辉").start(); } }
-
-
-
龟兔赛跑(我们是上帝)
public class Race implements Runnable { private static String name; @Override public void run() { for (int i = 0; i <= 100; i++) { //模拟兔子休息 if (Thread.currentThread().getName().equals("兔子") && i % 10 == 0) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } //判断比赛是否结束 boolean flag = gameOver(i); //如果比赛结束了,就结束程序 if (flag) { break; } System.out.println(Thread.currentThread().getName() + "--->跑了" + i + "步"); } } private boolean gameOver(int steps) { //判断是否由胜利者 if (name != null) { return true; } else if (steps == 100) { //已经存在是胜利者 name = Thread.currentThread().getName(); System.out.println("winner is " + name); return true; } return false; } public static void main(String[] args) { Race race = new Race(); new Thread(race, "兔子").start(); new Thread(race, "乌龟").start(); } }
-
实现Callable接口
-
实现Callable接口,需要返回值类型
-
重写call方法,需要抛出异常
-
创建目标对象
-
创建执行服务:ExecutorService ser=Executors.newFixedThreadPool(1);
-
提交执行:Future<Boolean> result1=ser.submit(t1);
-
获得结果:boolean r1=result1.get();
-
关闭服务:ser.shutdownNow();
package com.lyh.demo02; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.concurrent.*; 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 t1=new TestCallable("http://browser9.qhimg.com/bdm/0_0_100/t01b30dd1843479c87c.jpg","1.jpg"); TestCallable t2=new TestCallable("http://browser9.qhimg.com/bdm/0_0_100/t01b30dd1843479c87c.jpg","2.jpg"); TestCallable t3=new TestCallable("http://browser9.qhimg.com/bdm/0_0_100/t01b30dd1843479c87c.jpg","3.jpg"); //1. 创建执行服务: ExecutorService ser = Executors.newFixedThreadPool(3); //2. 提交执行: Future<Boolean> r1 = ser.submit(t1); Future<Boolean> r2 = ser.submit(t2); Future<Boolean> r3 = ser.submit(t3); //3. 获得结果: Boolean rs1 = r1.get(); Boolean rs2 = r2.get(); Boolean rs3 = r3.get(); //4. 关闭服务: 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方法出现问题"); } } }
-
-
-
-
线程状态
-
新建状态---就绪状态---运行状态---阻塞状态---就绪状态
-
新建状态---就绪状态---运行状态--就绪状态---死亡状态
-
线程停止
-
线程休眠
-
sleep(时间)指定当前线程阻塞的毫秒数
-
sleep存在异常InterruptedException
-
sleep时间达到后线程进入就绪状态
-
sleep可以模拟网络延迟,倒计时
-
每一个对象都有一个锁,sleep不会释放锁;
-
代码实现
package com.lyh.state; import java.text.SimpleDateFormat; import java.util.Date; public class TestSleep { //打印当前系统时间 public static void main(String[] args) { Date date = new Date(System.currentTimeMillis()); while (true){ try { Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH:mm:ss").format(date)); date = new Date(System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } } } //模拟倒计时时间 public static void tenDown() throws InterruptedException { int num=10; while (true){ Thread.sleep(10000); System.out.println(num--); if (num<=0){ break; } } } }
-
-
礼让
-
代码实现
public class TestYield implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"线程开始了"); //礼让方法 Thread.yield(); System.out.println(Thread.currentThread().getName()+"线程结束了"); } public static void main(String[] args) { TestYield yield = new TestYield(); new Thread(yield,"a").start(); new Thread(yield,"b").start(); } }
-
-
join()(开辟vip通道)
-
代码实现
package com.lyh.state; public class TestJoin implements Runnable { @Override public void run() { for (int i = 0; i < 10; 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 < 50; i++) { if (i == 200) { thread.join();//插队 } System.out.println("我是main" + i); } } }
-
-
State()观测线程状态
//观察线程状态 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); //观察后启动 thread.start(); state=thread.getState();//更新线程状态 System.out.println(state); //只要线程不终止,就一直执行state!=Thread.State.TERMINATED while (state!=Thread.State.TERMINATED){ Thread.sleep(100); state=thread.getState();//更新线程状态 System.out.println(state); } } }
-
线程优先级:setPriority():设置优先级
-
代码实现
/** * setPriority();设置优先级,最高为10 * getPriority() 获取优先级 */ public class TestPriority { public static void main(String[] args) { //主线程默认优先级 System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority()); myPriority myPriority = new myPriority(); Thread thread0 = new Thread(myPriority); Thread thread1 = new Thread(myPriority); Thread thread2 = new Thread(myPriority); //先设置优先级在启动 thread0.start(); thread1.setPriority(5); thread1.start(); thread2.setPriority(Thread.MAX_PRIORITY);//最高优先级 thread2.start(); } } class myPriority implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority()); } }
-
-
-
线程同步(重点)
-
对可能出现线程安全的代码,用锁把它锁定,代码执行完毕后释放锁,让其他线程进来执行。这样可以解决安全问题。不能让多个线程同时去操作共享的变量,在一个线程执行完代码前,不让其他线程进入执行代码。
-
synchronized锁,解决线程不安全(假设有三个线程t1、t2、t3,怎么保证让t1执行完毕后执行t2,t2执行完毕后执行t3线程?)
//假设有三个线程t1、t2、t3,怎么保证让t1执行完毕后执行t2,t2执行完毕后执行t3线程? public static void main(String[] args) { //1.子线程 Thread thread = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +"i:"+i); } } }); //2.子线程 Thread thread1 = new Thread(new Runnable() { @Override public void run() { try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 10; i++) { try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +"i:"+i); } } }); //3.子线程 Thread thread2 = new Thread(new Runnable() { @Override public void run() { try { thread1.join(); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 20; i++) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +"i:"+i); } } }); thread.start(); thread1.start(); thread2.start(); }
-
测试JUC安全类型的集合
public class TestJUC { public static void main(String[] args) throws InterruptedException { CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(); new Thread(() -> { for (int i = 0; i < 10000; i++) { list.add(Thread.currentThread().getName()); } }).start(); Thread.sleep(1000); System.out.println(list.size()); } }
-