多线程
1.第一种方式实现
//这是第一种方式,继承Thread类 /* ThreadOne tOne = new ThreadOne(); ThreadOne tTwo = new ThreadOne(); tOne.setName("线程1"); tTwo.setName("线程2"); tOne.start(); tTwo.start();*/
class ThreadOne extends Thread{ @Override public void run(){ for (int i = 0; i < 100; i++) { System.out.println("这是线程"+this.getName()); } } }
2.第二种方式实现
//这是第二种方式,实现接口方法 /* ThreadTwo ttOne = new ThreadTwo(); ThreadTwo ttTwo = new ThreadTwo(); Thread tOne = new Thread(ttOne); Thread tTwo = new Thread(ttTwo); tOne.setName("线程1"); tTwo.setName("线程2"); tOne.start(); tTwo.start();*/
class ThreadTwo implements Runnable{ @Override public void run( ) { for (int i = 0; i < 100; i++) { //因为不是继承类,所以无法通过getName去获得线程名字,Thread是一个类,所以自带静态方法。 //关注Api帮助文档,给你带来更多快乐 Thread thread = Thread.currentThread(); System.out.println("这是线程"+thread.getName()); } } }
3.第三种方式实现
class MyThread implements Callable<Integer>{ @Override public Integer call() throws Exception { int sum=0; for (int i = 0; i <= 100; i++) { sum = sum+i; } return sum; } }
//这是第三种方法,实现futureTask //创建一个类实现Callable对象,表示要执行的任务 MyThread mt = new MyThread(); //创建线程管理对象 FutureTask<Integer> ft = new FutureTask<>(mt); //创建线程 Thread thread = new Thread(ft); //线程启动 thread.start(); //通过ft.get() 得到线程运行结果 System.out.println(ft.get()); }
4.方法:
补充:子类要实现父类构造方法,这样才能通过构造方法去设置名称。
线程:
ThreadOne tOne = new ThreadOne("线程一"); ThreadOne tTwo = new ThreadOne("线程贰"); //设置线程的优先级,优先级越高,则抢夺CPU的概率越高,默认为5 tOne.setPriority(1); tTwo.setPriority(8); System.out.println(tOne.getPriority()); System.out.println(tTwo.getPriority()); tOne.start(); tTwo.start();
守护线程代码和场景:
yield():让出线程,让出后再竞争,尽可能均匀一点,但是不一定。
Join插入线程:
线程周期:
线程互斥问题:通过卖电影票实现 synchronized:称为同步代码块
//以下是互斥代码 Moive moive1 = new Moive("1"); Moive moive2 = new Moive("贰"); Moive moive3 = new Moive("三"); moive1.start(); moive2.start(); moive3.start();
class Moive extends Thread{ static int count = 1; public Moive() { } public Moive(String name) { super(name); } //定义一个全局变量,但是需要加一个 static 关键字,这样不管创建多少个对象都表示使用一个变量 //为了互斥买票且不出现多卖的情况,必须加锁,锁对象任意,但必须唯一,一般用 类名.class @Override public void run() { //互斥 //标红两句代码不能写反,否则一直是一个进程运行 while(count<=100){ synchronized (Moive.class){ Thread thread = Thread.currentThread(); try { thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(this.getName()+"售卖第"+count+"张票"); count++; } } } }
synchronized:同步代码块详解
//以下是互斥代码,第二种实现方式 MoiveTwo moive = new MoiveTwo(); Thread thread1 = new Thread(moive); Thread thread2 = new Thread(moive); Thread thread3 = new Thread(moive); thread1.setName("刘一手"); thread2.setName("王二狗"); thread3.setName("张三"); thread1.start(); thread2.start(); thread3.start();
class Moive extends Thread{ static int count = 1; public Moive() { } public Moive(String name) { super(name); } //定义一个全局变量,但是需要加一个 static 关键字,这样不管创建多少个对象都表示使用一个变量 //为了互斥买票且不出现多卖的情况,必须加锁,锁对象任意,但必须唯一,一般用 类名.class @Override public void run() { //互斥 while(count<=100){ synchronized (Moive.class){ Thread thread = Thread.currentThread(); try { thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(this.getName()+"售卖第"+count+"张票"); count++; } } } } //这是线程方法学习第二种实现,将锁代码的方法提取出来。 class MoiveTwo implements Runnable{ int count = 1; //定义一个全局变量,但是需要加一个 static 关键字,这样不管创建多少个对象都表示使用一个变量 //为了互斥买票且不出现多卖的情况,必须加锁,锁对象任意,但必须唯一,一般用 类名.class //但是这种情况下,类只会生成一个对象,所以可以不用Static,还有,这样代码运行会有问题,当count==100的时候,其他两个线程还会增加,所以还是的判断count>100;则直接退出 //继承Thread类的那种生成方式不能用这种提取方法:因为无法指定对象去锁定,所以无法用此方法 @Override public void run() { //互斥 while(count<=100){ setCount(); } } private synchronized void setCount() { Thread thread = Thread.currentThread(); try { thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println( thread.getName()+"售卖第"+count+"张票"); count++; } }
stringBuffer 和 stringBuilder :用法一样,但是前者考虑了线程安全问题。
5.提取代码块成为方法:ctrl+alt+m
6.ctrl+alt+T,补充很多好东西
7. Lock锁
代码
MoiveThree moive1 = new MoiveThree("1"); MoiveThree moive2 = new MoiveThree("贰"); MoiveThree moive3 = new MoiveThree("三"); moive1.start(); moive2.start(); moive3.start();
class MoiveThree extends Thread{ Thread thread = Thread.currentThread(); static ReentrantLock lock = new ReentrantLock(); static int count = 0; public MoiveThree() { } public MoiveThree(String name) { super(name); } //定义一个全局变量,但是需要加一个 static 关键字,这样不管创建多少个对象都表示使用一个变量 //为了互斥买票且不出现多卖的情况,必须加锁,锁对象任意,但必须唯一,一般用 类名.class @Override public void run() { //互斥 while(true){ lock.lock(); try { if(count ==100){ return; } thread.sleep(100); count++; System.out.println(this.getName()+"售卖第"+count+"张票"); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.unlock(); } } } }
8.生产者和消费者
注意点:加锁家的是同一把,不是给线程加锁。
public class ThreadWaitStudy { public static int tableState =1; public static int eatCount = 10; public static Object obj = new Object(); public static void main(String[] args) { Client client = new Client("客人"); Chef chef = new Chef("厨师"); client.start(); chef.start(); } } //客人类 class Client extends Thread{ public Client() { } public Client(String name) { super(name); } @Override public void run(){ while (true){ synchronized (ThreadWaitStudy.obj){ if(ThreadWaitStudy.eatCount ==0){ break; }else { if (ThreadWaitStudy.tableState == 0) { System.out.println("没面了,别吃了"); try { ThreadWaitStudy.obj.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } else { ThreadWaitStudy.eatCount--; System.out.println(currentThread().getName() + "还能吃" + ThreadWaitStudy.eatCount + "碗"); ThreadWaitStudy.obj.notify(); ThreadWaitStudy.tableState = 0; } } } } } } //厨师类 class Chef extends Thread{ public Chef() { } public Chef(String name) { super(name); } @Override public void run(){ while (true){ synchronized (ThreadWaitStudy.obj){ if(ThreadWaitStudy.eatCount == 0){ break; } else { if(ThreadWaitStudy.tableState == 1) { try { ThreadWaitStudy.obj.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } else { System.out.println(currentThread().getName() + "做好了面,快吃面"); ThreadWaitStudy.obj.notify(); ThreadWaitStudy.tableState = 1; } } } } } }
9.阻塞队列:定义队列,通过阻塞队列传值,应该也可以通过公共队列,这里没试过。
import java.util.concurrent.ArrayBlockingQueue; public class ThreadQueueStudy { public static void main(String[] args) { //定义阻塞队列的长度 ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(100); ClientOne clientOne = new ClientOne(queue); ChefOne chefOne = new ChefOne(queue); clientOne.start(); chefOne.start(); } } class ChefOne extends Thread{ ArrayBlockingQueue<String> queue; //通过构造装入值 public ChefOne(ArrayBlockingQueue<String> queue) { this.queue = queue; } @Override public void run() { while (true) { try { queue.add("面条"); } catch (Exception e) { e.printStackTrace(); } System.out.println(".........."); } } } //客人类 class ClientOne extends Thread { ArrayBlockingQueue<String> queue; //通过构造装入值 public ClientOne(ArrayBlockingQueue<String> queue) { this.queue = queue; } @Override public void run() { while (true) { try { System.out.println(queue.take()); } catch (InterruptedException e) { e.printStackTrace(); } } } }
10.线程里面要用集合
改进:集合写在run方法里,这样只需写一次。
11.线程池
实现必须用Runable接口类,否则好像管理不了。
代码:
任务执行顺序:
线程池 ----满了以后---->等待队列 ----满了以后----->临时线程 ----满了以后--->丢弃任务
代码:
//自定义创建 ThreadPoolExecutor executors = new ThreadPoolExecutor( 3, 6, 90, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() ); PoolClass poolClass1 = new PoolClass(); PoolClass poolClass2 = new PoolClass(); PoolClass poolClass3 = new PoolClass(); PoolClass poolClass4 = new PoolClass(); executors.submit(poolClass1); executors.submit(poolClass2); executors.submit(poolClass3); executors.submit(poolClass4);
12.制定合适线程池大小,没听懂
//获得电脑运行的最大线程数,方便定义线程池。
int systemThread = Runtime.getRuntime().availableProcessors(); System.out.println(systemThread);