创立和启动线程的形式一
- 自定义类继承Thread类并重写run办法,而后创立该类的对象调用start办法。
创立和启动线程的形式二
- 自定义类实现Runnable接口并重写run办法,创立该类的对象作为实参来结构Thread类型的对象,而后应用Thread类型的对象调用start办法。
public static void main(String[] args) { new Thread(){ @Override public void run() { System.out.println("t1"); } }.start(); new Thread(new Runnable() { @Override public void run() { System.out.println("t2"); } }).start(); new Thread(()->{ System.out.println("t3"); }).start();}
1.继承形式治理线程编号和名称
public class ThreadIdNameTest extends Thread{ public ThreadIdNameTest(String sun) { //调用父类的构造方法 super(sun); } @Override public void run() { System.out.println("子线程的ID:" + this.getId()); System.out.println("子线程的名称:" + getName()); } public static void main(String[] args) { ThreadIdNameTest t1 = new ThreadIdNameTest("sun"); t1.start(); System.out.println("主线程的ID:" + Thread.currentThread().getId()); System.out.println("主线程的名称:" + Thread.currentThread().getName()); }}===========主线程的ID:1子线程的名称:sun主线程的名称:main
2.接口的形式治理线程编号和名称
public class MainTest { public static void main(String[] args) { new Thread(()->{ System.out.println("子线程的ID:" + Thread.currentThread().getId()); System.out.println("子线程的名称:" + Thread.currentThread().getName()); Thread.currentThread().setName("tttt"); System.out.println("子线程的名称:" + Thread.currentThread().getName()); }).start(); System.out.println("主线程的ID:" + Thread.currentThread().getId()); System.out.println("主线程的名称:" + Thread.currentThread().getName()); }}===========子线程的ID:14主线程的ID:1子线程的名称:Thread-0主线程的名称:main子线程的名称:tttt
3.罕用的办法
Sleep
public class ThreadSleepTest extends Thread { private boolean flag = true; @Override public void run() { while (flag) { LocalDateTime now = LocalDateTime.now(); String time = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:ss:mm")); System.out.println(time); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { ThreadSleepTest t1 = new ThreadSleepTest(); t1.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } t1.flag = false; }}
守护线程
public class ThreadDaemonTest extends Thread{ @Override public void run() { //默认不是守护线程 //当子线程不是守护线程时,尽管主线程先完结了,然而子线程仍然会继续执行,直到打印所有数据为止 //当子线程是守护时,当主线程完结后,则子线程随之完结 for(int i = 0;i < 50;i++){ System.out.println("子线程:i = "+ i); } } public static void main(String[] args) { ThreadDaemonTest t1 = new ThreadDaemonTest(); //必须在线程启动之前设置子线程为守护线程 t1.setDaemon(true); t1.start(); for(int i = 0;i < 20;i++){ System.out.println("主线程:i = "+ i); } }}
join期待该线程终止
/** * @Author 振帅 * @Date 2021/05/26 21:49 */public class ThreadJoinTest { public static void main(String[] args) { //偶数 Thread t1 = new Thread(()->{ for(int i = 0;i < 100;i += 2){ System.out.println("ti==:" + i); } }); //奇数 Thread t2 = new Thread(()->{ for(int i = 1;i < 100;i += 2){ System.out.println("t2:" + i); } }); System.out.println("主线程开始"); t1.start(); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("主线程完结"); }}
线程同步机制
1.同步代码块实现线程同步形式一
- synchronized (dm)
/** * @Author 振帅 * @Date 2021/05/26 22:39 * synchronized 模仿取钱 */public class AccountRunnableTest implements Runnable{ class Demo { } //锁 Demo dm = new Demo(); //账户余额 private int balance; public AccountRunnableTest(int balance) { this.balance = balance; } public int getBalance() { return balance; } public void setBalance(int balance) { this.balance = balance; } @Override public void run() { System.out.println("线程" + Thread.currentThread().getName() + "已启动..."); //synchronized (new Demo()){ //锁不住 synchronized (dm){ //1.模仿从后盾查问余额 int temp = getBalance(); //2.模仿取款200 if (temp > 200) { System.out.println("正在出钞,请稍后..."); temp -= 200; try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("请取走你的钞票!"); } else { System.out.println("余额有余"); } //3.更新余额 setBalance(temp); } } public static void main(String[] args) { AccountRunnableTest account = new AccountRunnableTest(1000); Thread t1 = new Thread(account); Thread t2 = new Thread(account); t1.start(); t2.start(); System.out.println("主线程开始期待..."); try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("最终账户余额为:"+ account.getBalance()); }}
2.同步代码块实现线程同步形式二
- static 润饰锁
/** * @Author 振帅 * @Date 2021/05/26 22:39 * synchronized 模仿取钱 */public class AccountThreadTest extends Thread{ static class Demo { } //锁 属于类层级 所有对象共享一个 private static Demo dm = new Demo(); //账户余额 private int balance; public AccountThreadTest(int balance) { this.balance = balance; } public int getBalance() { return balance; } public void setBalance(int balance) { this.balance = balance; } @Override public void run() { System.out.println("线程" + Thread.currentThread().getName() + "已启动..."); synchronized (dm){ //1.模仿从后盾查问余额 int temp = getBalance(); //2.模仿取款200 if (temp > 200) { System.out.println("正在出钞,请稍后..."); temp -= 200; try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("请取走你的钞票!"); } else { System.out.println("余额有余"); } //3.更新余额 setBalance(temp); } } public static void main(String[] args) { AccountThreadTest at1 = new AccountThreadTest(1000); AccountThreadTest at2 = new AccountThreadTest(1000); at1.start(); at2.start(); System.out.println("主线程开始期待..."); try { at1.join(); at2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("at1账户余额为:"+ at1.getBalance()); System.out.println("at2账户余额为:"+ at2.getBalance()); }}
3.同步办法块实现线程同步形式一
- 应用synchronized锁住整个办法
/** * @Author 振帅 * @Date 2021/05/26 22:39 * synchronized 模仿取钱 */public class AccountRunnableTest implements Runnable{ //账户余额 private int balance; public AccountRunnableTest(int balance) { this.balance = balance; } public int getBalance() { return balance; } public void setBalance(int balance) { this.balance = balance; } @Override public synchronized void run() { System.out.println("线程" + Thread.currentThread().getName() + "已启动..."); //1.模仿从后盾查问余额 int temp = getBalance(); //2.模仿取款200 if (temp > 200) { System.out.println("正在出钞,请稍后..."); temp -= 200; try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("请取走你的钞票!"); } else { System.out.println("余额有余"); } //3.更新余额 setBalance(temp); } public static void main(String[] args) { AccountRunnableTest account = new AccountRunnableTest(1000); Thread t1 = new Thread(account); Thread t2 = new Thread(account); t1.start(); t2.start(); System.out.println("主线程开始期待..."); try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("最终账户余额为:"+ account .getBalance()); }}
该形式等价于:
synchronized(this) { 整个办法体的代码 }
this 代表调用run办法的对象,由源码可知 调用run办法的对象是account
因而 synchronized(this){} 能够锁住
@Overridepublic void run() { synchronized (this){ System.out.println("线程" + Thread.currentThread().getName() + "已启动..."); //1.模仿从后盾查问余额 int temp = getBalance(); //2.模仿取款200 if (temp > 200) { System.out.println("正在出钞,请稍后..."); temp -= 200; try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("请取走你的钞票!"); } else { System.out.println("余额有余"); } //3.更新余额 setBalance(temp); }}
4.同步办法块实现线程同步形式二
- 当咱们对一个静态方法加锁,如:
public synchronized static void xxx(){….} - 那么该办法锁的对象是类对象。每个类都有惟一的一个类对象。获取类对象的形式:类名.class。
- 静态方法与非静态方法同时应用了synchronized后它们之间是非互斥关系的。
- 起因在于:静态方法锁的是类对象而非静态方法锁的是以后办法所属对象。
/** * @Author 振帅 * @Date 2021/05/26 22:39 * synchronized */public class AccountThreadTest extends Thread{ //账户余额 private int balance; public AccountThreadTest(int balance) { this.balance = balance; } public int getBalance() { return balance; } public void setBalance(int balance) { this.balance = balance; } public synchronized static void test(){ System.out.println("线程" + Thread.currentThread().getName() + "已启动..."); System.out.println("正在出钞,请稍后..."); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("请取走你的钞票!"); } @Override public void run() { test(); } public static void main(String[] args) { AccountThreadTest at1 = new AccountThreadTest(1000); AccountThreadTest at2 = new AccountThreadTest(1000); at1.start(); at2.start(); System.out.println("主线程开始期待..."); try { at1.join(); at2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("at1账户余额为:"+ at1.getBalance()); System.out.println("at2账户余额为:"+ at2.getBalance()); }}
等价于
public static void test(){ synchronized(AccountThreadTest.class){ System.out.println("线程" + Thread.currentThread().getName() + "已启动..."); System.out.println("正在出钞,请稍后..."); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("请取走你的钞票!"); }}
5.应用Lock(锁)实现线程同步
- 从Java5开始提供了更弱小的线程同步机制—应用显式定义的同步锁对象来实现。
- java.util.concurrent.locks.Lock接口是管制多个线程对共享资源进行拜访的工具。
- 该接口的次要实现类是ReentrantLock类,该类领有与synchronized雷同的并发性,在当前的线程安全控制中,常常应用ReentrantLock类显式加锁和开释锁。
与synchronized形式的比拟
- Lock是显式锁,须要手动实现开启和敞开操作,而synchronized是隐式锁,执行锁定代码后主动
开释。 - Lock只有同步代码块形式的锁,而synchronized有同步代码块形式和同步办法两种锁。
- 应用Lock锁形式时,Java虚拟机将破费较少的工夫来调度线程,因而性能更好。
/** * @Author 振帅 * @Date 2021/05/26 22:39 * ReentrantLock 模仿取钱 */public class AccountRunnableTest implements Runnable{ //账户余额 private int balance; //筹备锁 private ReentrantLock lock = new ReentrantLock(); public AccountRunnableTest(int balance) { this.balance = balance; } public int getBalance() { return balance; } public void setBalance(int balance) { this.balance = balance; } @Override public void run() { //开始加锁 lock.lock(); System.out.println("线程" + Thread.currentThread().getName() + "已启动..."); //1.模仿从后盾查问余额 int temp = getBalance(); //2.模仿取款200 if (temp > 200) { System.out.println("正在出钞,请稍后..."); temp -= 200; try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("请取走你的钞票!"); } else { System.out.println("余额有余"); } //3.更新余额 setBalance(temp); //解锁 lock.unlock(); } public static void main(String[] args) { AccountRunnableTest account = new AccountRunnableTest(1000); Thread t1 = new Thread(account); Thread t2 = new Thread(account); t1.start(); t2.start(); System.out.println("主线程开始期待..."); try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("最终账户余额为:"+ account.getBalance()); }}
线程通信
1.Object类罕用的办法
办法申明 | 性能介绍 |
---|---|
void wait() | 用于使得线程进入期待状态,直到其它线程调用notify()或notifyAll()方 法 |
void wait(long timeout) | 用于进入期待状态,直到其它线程调用办法或参数指定的毫秒数曾经过来为止 |
void notify() | 用于唤醒期待的单个线程 |
void notifyAll() | 用于唤醒期待的所有线程 |
/** * @Author 振帅 * @Date 2021/05/26 23:53 * 线程通信 两个线程交替打印1-100 */public class ThreadCommunicateTest implements Runnable { private int cnt = 1; @Override public void run() { while (true) { synchronized (this){ //用于唤醒期待的单个线程 写在锁外面 notify(); if(cnt <= 100){ System.out.println("线程:"+ Thread.currentThread().getName() +"中的cnt:= " +cnt); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } cnt++; try { //用于使得线程进入期待状态,直到其它线程调用notify()或notifyAll()办法 写在锁外面 //以后线程打印完一个数 为了避免持续打印 调用wait() wait(); } catch (InterruptedException e) { e.printStackTrace(); } }else { break; } } } } public static void main(String[] args) { ThreadCommunicateTest tc = new ThreadCommunicateTest(); Thread t1 = new Thread(tc); Thread t2 = new Thread(tc); t1.start(); t2.start(); }}
2.生产者消费者模型实现
仓库类
/** * @Author 振帅 * @Date 2021/05/27 0:20 * 仓库类 */public class StoreHouse { //记录产品的数量 private int cnt = 0; //生产办法 public synchronized void produceProduct(){ notify(); if (cnt < 10) { System.out.println("线程"+Thread.currentThread().getName()+"正在生产第"+(cnt+1)+"个产品"); cnt++; } else { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } //生产办法 public synchronized void consumerProduct(){ notify(); if (cnt > 0) { System.out.println("线程"+Thread.currentThread().getName()+"正在生产第"+(cnt)+"个产品"); cnt--; } else { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } }}
生产者
/** * @Author 振帅 * @Date 2021/05/27 0:22 * 生产者 */public class ProduceThread extends Thread{ //申明一个仓库类型的援用作为成员变量,为了能调用仓库类中的生产办法 合成复用准则 private StoreHouse storeHouse; //为了确保两个线程共用一个仓库 public ProduceThread(StoreHouse storeHouse){ this.storeHouse = storeHouse; } @Override public void run() { while (true) { storeHouse.produceProduct(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } }}
消费者
/** * @Author 振帅 * @Date 2021/05/27 0:22 * 消费者 */public class ConsumerThread extends Thread{ //申明一个仓库类型的援用作为成员变量,为了能调用仓库类中的生产办法 合成复用准则 private StoreHouse storeHouse; //为了确保两个线程共用一个仓库 public ConsumerThread(StoreHouse storeHouse){ this.storeHouse = storeHouse; } @Override public void run() { while (true) { storeHouse.consumerProduct(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }}
测试类
/** * @Author 振帅 * @Date 2021/05/27 0:27 */public class StoreHouseTest { public static void main(String[] args) { //创立仓库类对象 StoreHouse storeHouse = new StoreHouse(); ProduceThread t1 = new ProduceThread(storeHouse); ConsumerThread t2 = new ConsumerThread(storeHouse); t1.start(); t2.start(); }}
创立和启动线程的形式三
- 实现Callable接口
- FutureTask类 extends RunnableFuture extends Runnable
/** * @Author 振帅 * @Date 2021/05/27 0:44 */public class ThreadCallableTest implements Callable<Integer> { @Override public Integer call() throws Exception { //计算1-10000之间累加和 int sum = 0; for (int i = 1;i <= 1000; i++){ sum = sum+i; } System.out.println("计算的后果为:" + sum); return sum; } public static void main(String[] args) { ThreadCallableTest tct = new ThreadCallableTest(); //用于形容可勾销的异步计算,该类提供了Future接口的根本实 //现,包含启动和勾销计算、查问计算是否实现以及检索计算结果的办法,也能够用于获取办法调用 //后的返回后果 FutureTask<Integer> task = new FutureTask<Integer>(tct); Thread th = new Thread(task); th.start(); Integer result = null; try { //获取call办法计算的后果 result = task.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("线程处理结果:" + result); }}
创立和启动线程的形式四
- Executors类
工具类和线程池的工厂类,能够创立并返回不同类型的线程池,罕用办法如下:
办法申明 | 性能介绍 |
---|---|
static ExecutorService newCachedThreadPool() | 创立一个可依据须要创立新线程的线程池 |
static ExecutorService newFixedThreadPool(int nThreads) | 创立一个可重用固定线程数的线程池 |
static ExecutorService newSingleThreadExecutor() | 创立一个只有一个线程的线程池 |
- ExecutorService接口
真正的线程池接口,次要实现类是ThreadPoolExecutor,罕用办法如下:
办法申明 | 性能介绍 |
---|---|
void execute(Runnable command) | 执行工作和命令,通常用于执行Runnable |
Future submit(Callable task) | 执行工作和命令,通常用于执行Callable |
void shutdown() | 启动有序敞开 |
public class ThreadPoolTest { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(10); ThreadCallableTest threadCallableTest = new ThreadCallableTest(); Future<Integer> future = executorService.submit(threadCallableTest); Integer result = null; try { result = future.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("线程处理结果:" + result); executorService.shutdown(); }}