多线程使用
多线程使用
线程生命周期及状态

| 常量 | 描述 |
|---|---|
| NEW | 尚未启动的线程处于此状态。 |
| RUNNABLE | 在Java虚拟机中执行的线程处于此状态。 |
| BLOCKED | 一个线程的线程状态阻塞等待监视器锁定。 处于阻塞状态的线程正在等待监视器锁定进入同步块/方法,或者在调用Object.wait后重新输入同步的块/方法。 |
| WAITING | 正在等待另一个线程执行特定动作的线程处于此状态。 |
| TIMED_WAITING | 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。 |
| TERMINATED | 已退出的线程处于此状态。 |
以上状态为Thread.State的常量
多线程的实现方式
简单实践
1、继承Thread类,重写run方法
MyThread mt1 = new MyThread();
mt1.start();
2、实现Runnable接口,实现run抽象方法
MyRunnable mr=new MyRunnable();
Thread t1= new Thread(mr);
t1.start();
3、实现Callable接口,实现call抽象方法,与Runnable接口不同的是Callable可以返回线程的执行结果
//方式1
MyCallable mc=new MyCallable();
FutureTask<String> ft=new FutureTask<>(mc);
Thread t1=new Thread(ft);
t1.start();
//方式2
MyCallable mc=new MyCallable();
//创建执行服务
ExecutorService ets = Executors.newFixedThreadPool(1);
//提交执行
Future<String> result=ets.submit(mc);
//获取结果
System.out.println(result.get());
//关闭服务
ets.shutdown();
多线程常用方法
| 方法 | 说明 |
|---|---|
| void setName(String xxx) | 设置线程的名称 |
| String getName() | 获取线程的名称 |
| void setPriority(int xx) | 设置线程的优先级,取值范围1-10,默认值为5 |
| static void sleep(1000) | 指定线程休眠,单位毫秒,不会释放当前已经拥有的锁 |
| void join() | 插队,等待该线程终止后其他线程才会执行, 阻塞其他线程 |
| static void yield() | 暂停当前正在执行的线程对象,但不阻塞,将线程转为就绪状态,让CPU重新调度,礼让不一定成功 |
| Thread.currentThread() | 获取当前运行的线程对象 |
| void setDaemon(boolean) | 守护线程,当普通线程结束后,守护线程也不会继续执行下去 |
| boolean isAlive() | 测试线程是否处于活动状态 |
静态代理
概念
静态代理模式总结:
1、真实对象和代理对象都要实现同一个接口
2、代理对象需要代理真实角色,所以需要真实角色
好处:
代理对象可以做很多真实对象做不了的事情
真实对象只需要专注自己的事情就好了
以下通过结婚案例说明,真实对象为人,代理对象为婚庆公司
代码实现
public class StaticProxy {
public static void main(String[] args) {
WeddingCompany wc = new WeddingCompany(new You());
wc.happyMarry();
}
}
interface Marry{
//定义开心的结婚
void happyMarry();
}
/**
* 真实人实现结婚方法:代理角色
*/
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("魔尊结婚了!");
}
}
/**
* 婚庆公司实现结婚方法,代理角色
*/
class WeddingCompany implements Marry{
/**
* 需要代理的对象
*/
private Marry target;
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void happyMarry() {
before(); //结婚之前
//结婚
this.target.happyMarry();
after(); //结婚之后
}
private void after() {
System.out.println("结婚后布置现场!");
}
private void before() {
System.out.println("结婚前收尾款!");
}
}
代码实测
规范的停止线程方法
public class ThreadTest implements Runnable{
/**
* 定义是否停止线程
*/
private boolean isStop = true;
@Override
public void run() {
while(isStop){
System.out.println(Thread.currentThread().getName()+"正在执行");
}
}
/**
* 停止线程
*/
public void stopThread(){
this.isStop = false;
}
public static void main(String[] args) throws InterruptedException {
ThreadTest tt = new ThreadTest();
new Thread(tt,"兔子").start();
for (int i = 0; i < 100; i++) {
Thread.sleep(10);
System.out.println(i);
if(i == 95){
System.out.println(i);
//进行线程停止
tt.stopThread();
}
}
}
}
不安全的抢票案例
public class Ticket implements Runnable{
public static void main(String[] args) {
Ticket t =new Ticket();
new Thread(t,"学生").start();
new Thread(t,"票贩子").start();
new Thread(t,"工人").start();
}
//定义20张票
private int ticket = 20;
@Override
public void run() {
while (true){
try {
if(!robTicket()){
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//抢票
private boolean robTicket() throws InterruptedException {
if(ticket<=0){
return false; //停止线程
}else{
//使用sleep放大出现问题的概率
Thread.sleep(30);
ticket --;
System.out.println(Thread.currentThread().getName()+"抢到了票,还剩下"+ticket+"张票!");
return true;
}
}
}
//结果,因为操作了共享对象,所以造成了线程不安全,数据一致性缺失
票贩子抢到了票,还剩下0张票!
学生抢到了票,还剩下-1张票!
工人抢到了票,还剩下-1张票!
使用synchronized加锁解决并发不安全问题
方法加锁
//抢票
private synchronized boolean robTicket() throws InterruptedException {
if(ticket<=0){
return false; //停止线程
}else{
ticket --;
System.out.println(Thread.currentThread().getName()+"抢到了票,还剩下"+ticket+"张票!");
return true;
}
}
代码块加锁==>代码块默认锁的this,可以自定义对象进行加锁
private boolean robTicket() throws InterruptedException {
synchronized (this) {
if (ticket <= 0) {
return false; //停止线程
} else {
ticket--;
System.out.println(Thread.currentThread().getName() + "抢到了票,还剩下" + ticket + "张票!");
return true;
}
}
}
自定义对象进行加锁
private final Object obj = new Object();
//抢票
private boolean robTicket() throws InterruptedException {
synchronized (obj) {
if (ticket <= 0) {
return false; //停止线程
} else {
ticket--;
System.out.println(Thread.currentThread().getName() + "抢到了票,还剩下" + ticket + "张票!");
return true;
}
}
}
使用lock加锁解决并发不安全问题
//定义lock锁对象
private final Lock lock = new ReentrantLock();
//抢票
private boolean robTicket() throws InterruptedException {
try {
lock.lock();
if (ticket <= 0) {
return false; //停止线程
} else {
//使用sleep放大出现问题的概率
Thread.yield();
ticket--;
System.out.println(Thread.currentThread().getName() + "抢到了票,还剩下" + ticket + "张票!");
return true;
}
}finally {
lock.unlock(); //一定要写在finally中,保证什么情况下都要释放锁
}
}
死锁案例
public class TestSiSuo implements Runnable{
//使用static保证资源只有一份,所有的实例对象都是同样的锁
static Chopsticks chopsticks = new Chopsticks();
static Bowl bowl = new Bowl();
private int id;
public TestSiSuo(int id) {
this.id = id;
}
@Override
public void run() {
while(true){
//执行
try {
havingDinner();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 定义吃饭方法,需要先拿到筷子和碗才能吃饭
*/
public void havingDinner() throws InterruptedException {
if(id == 0){
synchronized (chopsticks){
System.out.println(Thread.currentThread().getName()+"拿到了筷子!");
Thread.sleep(1000);
synchronized (bowl){
System.out.println(Thread.currentThread().getName()+"拿到了碗!");
}
}
System.out.println(Thread.currentThread().getName()+"开始吃饭了!");
}else{
synchronized (bowl){
System.out.println(Thread.currentThread().getName()+"拿到了碗!");
Thread.sleep(2000);
synchronized (chopsticks){
System.out.println(Thread.currentThread().getName()+"拿到了筷子!");
}
}
System.out.println(Thread.currentThread().getName()+"开始吃饭了!");
}
}
public static void main(String[] args) {
TestSiSuo ts =new TestSiSuo(0);
TestSiSuo ts1 =new TestSiSuo(1);
new Thread(ts,"小明").start();
new Thread(ts1,"小红").start();
}
}
class Chopsticks{
//筷子锁
}
class Bowl{
//碗锁
}
生产者和消费者案例(必须为同一把锁)
生产和消费方法在控制器内
package com.lwp.study.mythread;
/**
* 测试生产者和消费者
*/
public class TestScAndXf {
public static void main(String[] args) {
//定义控制器
Controller cl = new Controller();
//生产者启动
Producer pro = new Producer(cl);
pro.setName("厨师");
pro.start();
//消费者启动
Consumer cs = new Consumer(cl);
cs.setName("吃货");
cs.start();
}
}
/**
* 生产者对象
*/
class Producer extends Thread{
Controller cl;
public Producer(Controller cl){
this.cl = cl;
}
@Override
public void run() {
while(true){
if(cl.count<=0){
break;
}
//生产食物
try {
cl.production();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 消费者对象
*/
class Consumer extends Thread{
Controller cl;
public Consumer(Controller cl){
this.cl = cl;
}
@Override
public void run() {
while(true){
if(cl.count<=0){
break;
}
//消费食物
try {
cl.eat();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 定义控制器
*/
class Controller{
//定义信号提醒 true表示有吃的
public boolean bool = true;
//定义要生产几个
public int count = 10;
/**
* 定义生产方法
*/
public synchronized void production() throws InterruptedException {
if(bool){
//有吃的,等待
this.wait();
}else{
//生产
System.out.println(Thread.currentThread().getName()+"正在生产");
bool = true;
//生产完成提醒用户吃
this.notifyAll();
}
}
/**
* 定义吃方法
*/
public synchronized void eat() throws InterruptedException {
if(bool){
//有吃的,进行吃
System.out.println(Thread.currentThread().getName()+"正在吃烤串,还需要吃"+count+"串");
//吃完数量-1
count-- ;
bool = false;
this.notifyAll();
}else{
//等待
this.wait();
}
}
}
生产和消费方法在各自类中(使用控制器作为锁对象)
package com.lwp.study.mythread;
/**
* 测试生产者和消费者
*/
public class TestScAndXf {
public static void main(String[] args) {
//定义控制器
Controller cl = new Controller();
//生产者启动
Producer pro = new Producer(cl);
pro.setName("厨师");
pro.start();
//消费者启动
Consumer cs = new Consumer(cl);
cs.setName("吃货");
cs.start();
}
}
/**
* 生产者对象
*/
class Producer extends Thread{
Controller cl;
public Producer(Controller cl){
this.cl = cl;
}
@Override
public void run() {
while(true){
if(cl.count<=0){
break;
}
//生产食物
try {
production();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 定义生产方法
*/
public void production() throws InterruptedException {
synchronized (cl){
if(cl.bool){
//有吃的,等待
cl.wait(); //唤醒通过锁对象等待
}else{
//生产
System.out.println(Thread.currentThread().getName()+"正在生产");
cl.bool = true;
//生产完成提醒用户吃
cl.notifyAll(); //唤醒通过锁对象唤醒
}
}
}
}
/**
* 消费者对象
*/
class Consumer extends Thread{
Controller cl;
public Consumer(Controller cl){
this.cl = cl;
}
@Override
public void run() {
while(true){
if(cl.count<=0){
break;
}
//消费食物
try {
eat();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 定义吃方法
*/
public void eat() throws InterruptedException {
synchronized (cl){ //使用同一个控制器作为锁
if(cl.bool){
//有吃的,进行吃
System.out.println(Thread.currentThread().getName()+"正在吃烤串,还需要吃"+cl.count+"串");
//吃完数量-1
cl.count-- ;
cl.bool = false;
cl.notifyAll(); //唤醒通过锁对象唤醒
}else{
//等待
cl.wait(); //唤醒通过锁对象等待
}
}
}
}
/**
* 定义控制器
*/
class Controller{
//定义信号提醒 true表示有吃的
public boolean bool = true;
//定义要生产几个
public int count = 10;
}
线程池
package com.lwp.study.mythread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
public static void main(String[] args) {
//创建线程池,容量为3
ExecutorService es = Executors.newFixedThreadPool(3);
//运行
es.execute(new Thread( () -> System.out.println(Thread.currentThread().getName())));
es.execute(new Thread( () -> System.out.println(Thread.currentThread().getName())));
es.execute(new Thread( () -> System.out.println(Thread.currentThread().getName())));
//超出线程池容量的则在任务队列等待执行
es.execute(new Thread( () -> System.out.println(Thread.currentThread().getName())));
es.execute(new Thread( () -> System.out.println(Thread.currentThread().getName())));
//关闭连接
es.shutdown();
}
}

浙公网安备 33010602011771号