Thread, Runnable, Callable
/** * 注意: 线程开启不一定立即执行, 由CPU调度执行 */ //创建线程方式一: 继承Thread类, 重新run 方法, 调用start开启线程 public class TestThread1 extends Thread{ @Override public void run() { //run 方法线程体 for (int i = 0; i < 20; i++) { System.out.println("run:"+i); } } //main线程, 主线程 public static void main(String[] args) { //创建线程对象 TestThread1 testThread1 = new TestThread1(); //调用start 方法开启线程 testThread1.start(); for (int i = 0; i < 20; i++) { System.out.println("main:"+i); } } }
package com.ccc.lesson01; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.URL; //多线程同步下载图片 public class TestThread2 extends Thread{ private String url;//图片地址 private String name;//方法名 public TestThread2(String url, String name) { this.url = url; this.name = name; } @Override public void run() { WebDownLoad webDownLoad = new WebDownLoad(); webDownLoad.download(url,name); System.out.println("下载图片名字为:"+name); } public static void main(String[] args) { TestThread2 t1 = new TestThread2("https://https://www..com/sss1.png", "1.png"); TestThread2 t2 = new TestThread2("https://www..com/sss2.png", "2.png"); TestThread2 t3 = new TestThread2("https://www..com/sss3.png", "3.png"); t1.start(); t2.start(); t3.start(); } } class WebDownLoad{ //下载方法 public void download(String url,String name){ try { //使用工具包下载 FileUtils.copyURLToFile(new URL(url),new File(name)); } catch (IOException e) { e.printStackTrace(); System.out.println("IO异常,download方法异常"); } } } //控制台 下载同时进行 下载图片名字为:2.png 下载图片名字为:1.png 下载图片名字为:3.png
//方式2 , 实现Runnable接口 public class TestThread21 implements Runnable{ @Override public void run() { //run 方法线程体 for (int i = 0; i < 500; i++) { System.out.println("run:"+i); } } //main线程, 主线程 public static void main(String[] args) { //创建Runnable接口的实现类对象 TestThread21 testThread21 = new TestThread21(); //创建线程对象, 通过线程对象来开启线程-------代理 // Thread thread = new Thread(testThread21); // thread.start(); new Thread(testThread21).start(); for (int i = 0; i < 20; i++) { System.out.println("main:"+i); } } }
package com.ccc.lesson02callable; import com.ccc.lesson01.TestThread12; 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() throws Exception { WebDownLoad webDownLoad = new WebDownLoad(); webDownLoad.download(url,name); System.out.println("下载图片名字为:"+name); return true; } public static void main(String[] args) throws ExecutionException, InterruptedException { TestCallable t1 = new TestCallable("https://gi", "1.png"); TestCallable t2 = new TestCallable("https://gi", "2.png"); TestCallable t3 = new TestCallable("https://gi", "3.png"); //创建执行服务 ExecutorService ser = Executors.newFixedThreadPool(1); Future<Boolean> r1 = ser.submit(t1); Future<Boolean> r2 = ser.submit(t2); Future<Boolean> r3 = ser.submit(t3); //获取结果 Boolean b1 = r1.get(); Boolean b2 = r2.get(); Boolean b3 = r3.get(); //关闭服务 ser.shutdownNow(); } } class WebDownLoad{ //下载方法 public void download(String url,String name){ try { //使用工具包下载 FileUtils.copyURLToFile(new URL(url),new File(name)); } catch (IOException e) { e.printStackTrace(); System.out.println("IO异常,download方法异常"); } } }
实现Runnable接口
实现Callable接口
//多线程同时操作同一个对象 //买火车票 //线程不安全 public class TestThread22 implements Runnable { //票数 private int ticketNums = 10; @Override public void run() { while (true) { if (ticketNums<=0){ break; } try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums--+"张"); } } public static void main(String[] args) { TestThread22 tt = new TestThread22(); new Thread(tt,"小明").start(); new Thread(tt,"小红").start(); new Thread(tt,"小绿").start(); } }
1,首先来个賽道距离,然后要离终点越来越近
2,判断比赛是否结束
3.打印出胜利者
4,龟兔赛跑开始
5,故事中是乌龟赢的,兔子需要睡觉,所以我们来模拟兔子睡觉
6,终于,乌龟赢得比赛
import java.util.Random; public class Race implements Runnable{ //static保证只有一个, 共享 , final 不变 private static String winner; //兔子每次跑几步 private int rabbit; //跑多少步 private int count; private Random random =new Random(); public Race(int rabbit, int count) { if (rabbit<=0){ rabbit = 1; } this.rabbit = rabbit; this.count = count; } @Override public void run() { for (int i = 1; i <= count; i++) { //判断比赛是否结束 boolean flag = gameOver(i); if (flag){ break; } //兔子休息 if (Thread.currentThread().getName().equals("兔子")){ if ( random.nextInt()%5 ==1){ try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } //让兔子步数不超过总长度 if ((count-i)<rabbit){ i+=count-i-1; } //兔子速率提高 if ((count-i)>rabbit){ i+=rabbit-1; } } System.out.println(Thread.currentThread().getName()+"跑了几步:"+i); } } private boolean gameOver(int setps){ //判断是否有胜利者 if (winner!=null){ return true; } if (setps >=count){ winner = Thread.currentThread().getName(); System.out.println("winner is" +winner); return true; } return false; } public static void main(String[] args) { //3:速度;兔子每次跑几步. 100:赛道长度 Race race = new Race(3,100); // Race race = new Race(8000000,100000000); new Thread(race,"兔子").start(); new Thread(race,"乌龟").start(); } }
package com.ccc.statiproxy; public class StaticProxy { public static void main(String[] args) { //结婚对象 You you = new You(); //婚庆公司, 代理 WeddingCompany weddingCompany = new WeddingCompany(you); //结婚 weddingCompany.marry(); //简化 new WeddingCompany(new You()).marry(); //启动线程 new Thread( ()-> System.out.println("跑起来")).start(); } } interface Marry{ //结婚方法 void marry(); } class You implements Marry{ @Override public void marry() { System.out.println("我结婚了"); } } class WeddingCompany implements Marry{ //代理人 private Marry person; public WeddingCompany(Marry person) { this.person = person; } @Override public void marry() { before(); //代理 this.person.marry(); after(); } private void before() { System.out.println("结婚前活动"); } private void after() { System.out.println("结婚后活动"); } }
new Thread ( () -> {System.out.print("正义执行")}).start();
public class TestLambda01 { //内部类 static class ClLike1 implements IfLike{ @Override public void Like() { System.out.println("Lambda--内部类"); } } public static void main(String[] args) { IfLike ifLike = null; //外部类 ifLike = new ClLike(); ifLike.Like(); //内部类 ifLike = new ClLike1(); ifLike.Like(); //局部内部类 class ClLike2 implements IfLike{ @Override public void Like() { System.out.println("Lambda--局部内部类"); } } ifLike = new ClLike2(); ifLike.Like(); //匿名内部类 IfLike ifLike2 = new IfLike() { @Override public void Like() { System.out.println("Lambda--匿名内部类"); } }; ifLike2.Like(); //Lambda表达式 相当于简化了匿名内部类 IfLike ifLike3 = ()->{ System.out.println("Lambda--Lambda表达式"); }; ifLike3.Like(); //如果Lambda表达式只有一行代码可以省略括号{} IfLike ifLike4 =() ->System.out.println("Lambda--Lambda表达式2"); ifLike4.Like(); //Lambda表达式,带参 IfLike2 if2 = null; if2 = (int a,int b)->{ System.out.println("Lambda--"+a+"-"+b); }; if2.Like(520,502); //单参数可以省略括号() //if2 = a-> System.out.println("Lambda--"+a); //可以省略掉数据类型 if2 = (a,b)-> System.out.println("Lambda--"+a+"-"+b); if2.Like(5200,5020); } } //函数式接口 interface IfLike{ void Like(); } interface IfLike2 { void Like(int a,int b); } class ClLike implements IfLike{ @Override public void Like() { System.out.println("Lambda--"); } }
创建, 就绪,阻塞,运行,死亡
package com.ccc.lesson05stop; /** * 测试线程停止 * 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"+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 < 2000; i++) { System.out.println("main"+i); if (i==1900){ testStop.stop(); System.out.println("停止"); break; } } } }
import java.text.SimpleDateFormat; import java.util.Date; import java.util.logging.SimpleFormatter; import java.util.zip.DataFormatException; public class TestSleep { public static void main(String[] args) throws InterruptedException { // sleep(); //获取系统时间 while (true){ Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH:mm:ss") .format(new Date(System.currentTimeMillis()))); } } //模拟倒计时 public static void sleep() throws InterruptedException { int num = 10; while (true) { Thread.sleep(1000); System.out.println(num--); if (num == 0) { break; } } } }
//礼让不一定成功 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()+"结束"); }
public class TestJoin implements Runnable{ @Override public void run() { for (int i = 0; i < 100; 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); } } }
线程状态。线程可以处于以下状态之一:
NEW
RUNNABLE
BLOCKED
WAITING
TIMED_WAITING
TERMINATED
一个线程可以在给定时间点处于一个状态。 这些状态是不反映任何操作系统线程状态的虚拟机状态。
package com.ccc.lesson05join; 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);//RUNNABLE //TERMINATED 线程终止状态 while (state != Thread.State.TERMINATED) { Thread.sleep(500); state = thread.getState(); System.out.println(state);//TIMED_WAITING----TERMINATED } } }
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。
线程的优先级用数字表示,范围从1-10. 10最高
Thread.MIN PRIORITY= 1
;Thread.MAX PRIORITY = 10;
Thread.NORM PRIORITY= 5;
使用以下方式改变或获取优先级
getPriority(). setPriority(int xxx)
注意:
package com.ccc.lesson05state; public class TestPriority implements Runnable { public static void main(String[] args) { //获取main线程的优先级 System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()); TestPriority testPriority = new TestPriority(); Thread thread1 = new Thread(testPriority,"thread1"); Thread thread2 = new Thread(testPriority,"thread2"); Thread thread3 = new Thread(testPriority,"thread3"); Thread thread4 = new Thread(testPriority,"thread4"); Thread thread5 = new Thread(testPriority,"thread5"); thread1.start(); thread2.setPriority(9); thread2.start(); thread3.setPriority(3); thread3.start(); thread4.setPriority(10); thread4.start(); thread5.setPriority(1); thread5.start(); /* 结果 main:5 thread1:5 thread3:3 thread5:1 thread4:10 thread2:9 */ } @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()); } }
public static void main(String[] args) { Thread threadUser = new Thread(() -> { for (int i = 0; i < 100; i++) { System.out.println("用户线程" + i); } }); Thread threadDaemon = new Thread(() -> { while (true){ System.out.println("守护守护---"); } }); threadDaemon.setDaemon(true); threadUser.start(); threadDaemon.start();//用户进程结束了,守护进程也随之结束 }
多个线程操作同一个线程
并发:同一个对象被多个线程同时操作
队列和锁
由于我们可以通过private关键字来保证数据对象只能被方法访问,所以我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:
public synchronized void method(int args) {}
◆synchronized方法控制对“对象”的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行
缺陷:若将-个大的方法申明为synchronized将会影响效率
//买火车票 public class UnSafeBuyTicket extends Thread{ private int ticket = 10; private boolean flag =true; @Override public void run() { while (flag) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } buy(); } } //买票方法, synchronized 同步方法, 锁的是this public synchronized void buy(){ if (ticket<=0){ flag=false; return; } System.out.println(Thread.currentThread().getName()+"买到了票"+ticket--); } public static void main(String[] args) { UnSafeBuyTicket tt = new UnSafeBuyTicket(); new Thread(tt,"小红").start(); new Thread(tt,"小明").start(); new Thread(tt,"小白").start(); } } _________________________________________________________________________________________ //银行取钱 public class UnSafeBanke { public static void main(String[] args) { Acount ac = new Acount("第一桶金", 100); Money m1 = new Money(ac, 100, "我"); Money m2 = new Money(ac, 50, "你"); m1.start(); m2.start(); } } //账户 class Acount{ String name; int money; public Acount(String name, int money) { this.name = name; this.money = money; } } //取钱 class Money extends Thread{ private int drawNum; private String drawName; private int nowMoney; Acount acount; public Money(Acount acount, int drawNum, String name) { super(name); this.acount = acount; this.drawNum = drawNum; } //取钱 @Override public void run() { //添加同步块 锁的对象是有变化的量 synchronized(acount){ if (acount.money-drawNum<0){ System.out.println(Thread.currentThread().getName()+"钱不够"); return; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //卡里余额 = 余额- 取钱数 acount.money -=drawNum; nowMoney +=drawNum; System.out.println(acount.name+"账户余额:"+acount.money); System.out.println(this.getName()+"取了:"+drawNum+"手里有:"+nowMoney); } } } ___________________________________________________________________________________________ //list public class UnSafeList { public static void main(String[] args) { List<String> list = new ArrayList<>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ synchronized(list){ list.add(Thread.currentThread().getName()); } }).start(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list.size()); } }
public class TestJuc { public static void main(String[] args) throws InterruptedException { CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ list.add(Thread.currentThread().getName()); }).start(); } Thread.sleep(1000); System.out.println(list.size()); } }
产生死锁的四个必要条件: .
生产者消费者模式
Java提供了几个方法解决线程之间的通信问题
方法名 | 作用 |
---|---|
wait() | 表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁 |
wait(long timeout) | 指定等待的毫秒数 |
notify() | 唤醒一个处于等待状态的线程 |
notifyAll() | 唤醒同一个对象上所有调用wait()方法的线程,优先级高的线程优先调度 |
注意:
lllegalMonitorStateException
解决方式:
package com.ccc.lesson08cooperation; public class TestPc { public static void main(String[] args) { SynContainer synContainer = new SynContainer(); new Producer(synContainer).start(); new Consumer(synContainer).start(); } } //生产者 class Producer extends Thread{ SynContainer syn ; public Producer(SynContainer syn) { this.syn = syn; } //生产 只负责生产 @Override public void run() { for (int i = 0; i < 100; i++) { syn.pushChicken(new Chicken(i)); System.out.println("生产了一只鸡,id:"+i); } } } //消费者 class Consumer extends Thread{ SynContainer syn ; public Consumer(SynContainer syn) { this.syn = syn; } //消费. 只负责消费 @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("消费了一只鸡,id:"+syn.consumption().id); } } } //缓冲区 class SynContainer{ Chicken[] chickens = new Chicken[10]; int count=0;//计数器 //生产者放入产品 public synchronized void pushChicken(Chicken chicken) { //如果容器满了,通知需要等待消费者来消费 if (count==chickens.length){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //如果没有满,我们就需要丢入产品 chickens[count] = chicken; count++; //丢入产品后,有产品了可以通知消费者了 this.notifyAll(); } //消费者拿产品 public synchronized Chicken consumption() { //如果没有产品就等待, 等生产者生产 if (count==0){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //先减, 因为生产者生产第十只鸡后,count变成了10就等待了,这里消费减去再释放 count--; Chicken chicken= chickens[count]; //吃完以后释放 this.notifyAll(); return chicken; } } //产品 class Chicken{ int id;//产品id public Chicken(int id) { this.id = id; } }
package com.ccc.lesson08cooperation; public class TestPcFlag { public static void main(String[] args) { Restaurant synContainer = new Restaurant(); new Producer(synContainer).start(); new Consumer(synContainer).start(); } } //生产者 class Producer extends Thread{ Restaurant syn ; public Producer(Restaurant syn) { this.syn = syn; } //生产 只负责生产 @Override public void run() { for (int i = 0; i < 100; i++) { syn.pushChicken(new Chicken(i)); System.out.println("生产了一只鸡,id:"+i); } } } //消费者 class Consumer extends Thread{ Restaurant syn ; public Consumer(Restaurant syn) { this.syn = syn; } //消费. 只负责消费 @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("消费了一只鸡,id:"+syn.consumption().id); } } } //餐厅 class Restaurant{ //用于存放一只鸡 Chicken chicken1 ; private boolean flag = true; //flag为true,没有鸡,生产者生产,消费者等候 //生产者放入产品 public synchronized void pushChicken(Chicken chicken) { //有鸡了就等待 if (!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //没有鸡,生产一只 chicken1 = chicken; flag=!flag;//变换状态 this.notifyAll(); } //消费者拿产品 public synchronized Chicken consumption() { //刚开始没有生产, 等生产者生产 if (flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //有鸡就,吃一只 Chicken chicken= chicken1; flag=!flag;//变换状态 //吃完以后释放 this.notifyAll(); return chicken; } } //产品 class Chicken{ int id;//产品id public Chicken(int id) { this.id = id; } }
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; //测试线程池 public class TestPool { public static void main(String[] args) { //1 创建服务, 设置线程池大小 ExecutorService service = Executors.newFixedThreadPool(5); //2 执行 使用线程池中的线程执行 service.execute(new MyThead()); service.execute(new MyThead()); service.execute(new MyThead()); service.execute(new MyThead()); service.execute(new MyThead()); //3 关闭连接 service.shutdown(); } } class MyThead implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }
new MyThread().start()
new Thread( new Mythread() ).start()
;FutureTask<obj> task = new FutureTask<obj>( new MyThread());
new Thread ( task ).start();
task.get();
synchronized (多线程操作的对象) {}
ReentrantLock lock = new ReentrantLock();
lock.lock();
,释放锁lock.unlock()
;