常用方法
线程内自身方法: | |
---|---|
Thread.currentThread().getName(); | 获取当前线程对象/并获取当前对象名 |
Thread.sleep(20); | 延迟执行时间 单位毫秒 |
Thread.yield(); | 收回当前执行线程,下次获取到线程后执行上次未完代码 |
线程通信: | |
wait(); | 使当前线程进入等待状态 |
notify(); | 随机解除一个等待状态线程 |
notifyAll(); | 解除全部等待状态线程 |
线程安全: | |
synchronized(共享锁对象){代码块} | 共享锁:自动锁,执行完毕自动解锁; |
private Lock l = new ReentrantLock(); | 创建Lock手动锁; |
l.lock(); | 加锁; |
l.unlock(); | 解锁; |
线程外调用方法: | |
---|---|
a.start(); | 启用a线程 |
a.join() | 将a线程拉回主线程执行 |
a.setDaemon(true) | 设置a为守护线程(守护的线程一旦结束那么守护线程也同时结束) |
三种创建多线程的方法:
第一种: 继承Thread类 第二种: 实现Runnable接口 第三种: 实现Callable接口
-
多线程常用方法:
线程定义:
线程,又称轻量级进程(Light Weight Process) 线程是进程中的一条执行路径,也是CPU的基本调度单位。若一个程序可同一时间执行多个线程,就是支持多线程的. 一个进程由一个或多个线程组成,彼此间完成不同的工作(任务),同时执行,称为多线程。
为什么使用多线程:
多线程能提高cpu的利用率,提升运行效率;
创建多线程:
Java中提供了三种实现多线程的方式:
第一种: 继承Thread类
第二种: 实现Runnable接口
第三种: 实现Callable接口(有返回值)
Thread:
package com.gzx.thread; //继承Thread类 public class MyThreadOne extends Thread{ //重写run()方法 @Override public void run() { System.out.println("线程1正在执行"); //获取当前线程对象 获取对象名 Thread.currentThread().getName(); } } }
package com.gzx; import com.gzx.thread.MyThreadOne; import com.gzx.thread.MyThreadTwo; public class Main { public static void main(String[] args) { System.out.println("主线程启动"); //引入线程对象 MyThreadOne myThreadOne = new MyThreadOne(); //启用该对象线程 myThreadOne.start(); } }
Runnable:
package com.gzx.runnable; //实现Runnable接口 public class MyRunnableOne implements Runnable{ //重写run()方法 @Override public void run() { System.out.println("MyRunnableOne is running"); } }
package com.gzx; import com.gzx.runnable.MyRunnableOne; public class MainTwo { public static void main(String[] args) { //引入线程对象 MyRunnableOne myRunnableOne = new MyRunnableOne(); //封装线程对象并命名 Thread t1 = new Thread(myRunnableOne,"线程A"); //开启该对象线程 t1.start(); System.out.println("主线程执行"); } }
Callable:
package com.gzx.callable; import java.util.concurrent.Callable; //实现Callable<类>接口 public class MyCallableOne implements Callable<Integer> { //重写call()方法 @Override public Integer call() throws Exception { // 定义一个整数变量nums,初始值为0 Integer nums = 0; // 使用for循环,循环条件为3*i<1000,循环变量i从0开始 for (int i = 0; 3*i <= 1000; i++) { // 将3*i的值加到nums上 nums+=3*i; } // 返回nums的值 return nums; } }
package com.gzx; import com.gzx.callable.MyCallableOne; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class MainThree { public static void main(String[] args) throws ExecutionException, InterruptedException { //创建多线程对象 MyCallableOne myCallableOne = new MyCallableOne(); //把call对象封装到FutureTask类中 //而且任务执行的结果也在FutureTask FutureTask task = new FutureTask(myCallableOne); Thread thread = new Thread(task); //开启该对象线程 thread.start(); //获取该对象返回值 Object o = task.get(); //输出 System.out.println(o); } }
线程安全:
线程安全引发原因:
当多个线程操作同一个资源时,则出现线程安全问题。
如何解决线程安全问题
使用锁相对于把原来的异步转换为同步操作(并行转换为串行)
(1):synchronized可以使用代码块和方法。自动加锁和释放锁。不会出现死锁问题。
(2):lock手动锁它只能使用在代码块中。需要手动加锁和释放锁。如果不释放锁,死锁问题。灵活。它的释放锁必须放在finally.
使用synchronized自动锁
可用于方法或代码块中
synchronized(共享锁对象){ 同步代码块。 }public synchronized void sell(){ if (tick > 0) { try { Thread.sleep(20); } catch (InterruptedException e) { throw new RuntimeException(e); } tick--; System.out.println(Thread.currentThread().getName() + "卖了一张票;剩余:" + tick + "张"); } }使用Lock手动锁。
Lock它是一个接口,它的实现类。ReentrantLock
public class SellTicket implements Runnable { private int tick = 100; private Lock l = new ReentrantLock(); @Override public void run() { while (true) { try { l.lock();//加锁 if (tick > 0) { try { Thread.sleep(20); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(Thread.currentThread().getName()+(--tick)); } else { break; } } finally { l.unlock();//解锁 } } } }
死锁:
线程A拥有锁a,希望获取锁b,线程B拥有锁b,希望获取锁a。 两个线程互相拥有对方希望获取的锁资源。可能会出现程序堵塞。从而造成死锁。
1. 不要使用锁嵌套。 2. 设置超时时间。--Lock类中tryLock. 3. 使用安全java.util.concurrent下的类。
线程通信:
wait方法:
wait方法(使当前线程进入等待状态)需要写入锁中
notify方法:
直接使用notify随机解除一个等待状态中的线程
使用notifyAll解除全部等待状态中的线程
public class MyRunnableOne implements Runnable{ @Override public void run() { for (int j = 0; j < 10; j++) { if(Thread.currentThread().getName()=="线程A"){ //调用进入等待状态方法 waits(); }else { //调用解除等待方法 addMoney(); } } } public synchronized void waits(){ try { //使当前线程进入等待状态 wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } public synchronized void addMoney(){ notifyAll();//解除全部等待线程 } }
线程状态:
状态名 | 通过调用不同的方法相互转换 |
---|---|
NEW | 新建状态 |
RUNNABLE | 就绪状态和运行状态 |
BLOCKED | 堵塞状态 |
WAITING | 等待状态 |
TIMED_WAITING | 时间等待 |
TERMINATED | 终止 |
各方法调用均需要经过运行状态BUNNABLE