创建方式
方式一:继承Thread类,重写run方法,调用start方法开启线程
package com.yyb.demo1;
//线程开启不一定立即执行 由cpu调度
public class TestThread1 extends Thread {
@Override
public void run() {
super.run();
//run方法线程体
}
public static void main(String[] args) {
TestThread1 testThread1=new TestThread1();
testThread1.start(); //和主线程同时执行
//主线程
System.out.println("我再学习多线程"+i);
}
}
方式二:实现Runable接口
package com.yyb.demo1;
public class TestThread3 implements Runnable{
@Override
public void run() {
System.out.println("执行了run方法");
//run方法线程体
}
public static void main(String[] args) {
TestThread3 testThread1=new TestThread3();
Thread thread=new Thread(testThread1);
thread.start();
//主线程
System.out.println("我再学习多线程"+i);
}
}
方式三:实现callable接口 (callable可以定义返回值,如下以下载图片为例)
package com.yyb.demo2;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
/**
* callable可以定义返回值
* 可以抛出异常
*/
public class TestCallable implements Callable<Boolean> {
@Override
public Boolean call() {
WebDowloader webDowloader=new WebDowloader();
webDowloader.dowloader(url,name);
return true; //返回值设为true
}
private String url;
private String name;
public TestCallable(String url,String name){
this.name=name;
this.url=url;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable t1=new TestCallable("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fa2.att.hudong.com%2F27%2F81%2F01200000194677136358818023076.jpg&refer=http%3A%2F%2Fa2.att.hudong.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1613376811&t=3302b442424575e914e7cd00767dd6bf","1.jpg");
TestCallable t2=new TestCallable("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fa2.att.hudong.com%2F27%2F81%2F01200000194677136358818023076.jpg&refer=http%3A%2F%2Fa2.att.hudong.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1613376811&t=3302b442424575e914e7cd00767dd6bf","2.jpg");
TestCallable t3=new TestCallable("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fa2.att.hudong.com%2F27%2F81%2F01200000194677136358818023076.jpg&refer=http%3A%2F%2Fa2.att.hudong.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1613376811&t=3302b442424575e914e7cd00767dd6bf","3.jpg");
//创建执行服务
ExecutorService service= Executors.newFixedThreadPool(3); //设置线程池为3
/**
实现线程池也可以实现runable接口 也可以定义返回值
使用 service.execute(new MyTheard());方式实现
*/
//提交执行
Future<Boolean> r1=service.submit(t1);
Future<Boolean> r2=service.submit(t2);
Future<Boolean> r3=service.submit(t3);
//获取结果
boolean re1=r1.get();
boolean re2=r2.get();
boolean re3=r3.get();
//关闭服务
service.shutdown();
}
}
class WebDowloader{
public void dowloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name)); //下载网络图片并重命名
} catch (IOException e) {
e.printStackTrace();
System.out.println("下载器出现异常");
}
}
}
线程安全问题
方式一:synchronized
- 使用方法一:
private synchronized void buy() throws InterruptedException {
//判断是否有票
if(ticket<=0){
flag=false;
return;
}
//模拟延时
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+"拿到"+ticket--);
}
- 使用方法二
synchronized (acount){
if(acount.money-drawingmoney<0){
System.out.println(Thread.currentThread().getName()+"没钱了");
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//卡内余额
acount.money=acount.money-drawingmoney;
//你手里的钱
nowmoney=nowmoney+drawingmoney;
System.out.println(acount.name+"余额为"+acount.money);
System.out.println(this.getName()+"手里的钱"+acount.money);
}
- 使用线程安全的一些类
package com.yyb.demo4;
import java.util.concurrent.CopyOnWriteArrayList;
public class TestJUC {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<String>(); //这个类本身是线程安全的
for (int i = 0; i < 1000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
死锁问题
1.使用synchronized结局
package com.yyb.demo5;
//死锁
public class ReadLock {
public static void main(String[] args) {
MakeUp g1=new MakeUp(0,"灰姑凉");
MakeUp g2=new MakeUp(1,"白雪公主");
g1.start();
g2.start();
}
}
//口红
class Lisptick{
}
//镜子
class Mirror{
}
class MakeUp extends Thread {
static Lisptick lisptick=new Lisptick();
static Mirror mirror=new Mirror();
int choice;
String girlName;
MakeUp(int choice,String girlName){
this.choice=choice;
this.girlName=girlName;
}
@Override
public void run() {
//化妆
try {
makeup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//化妆 互相持有对方的锁
private void makeup() throws InterruptedException {
if(choice==0){
synchronized (lisptick){ //获得口红的锁
System.out.println(this.girlName+"获得口红");
Thread.sleep(1000);
}
synchronized (mirror){
System.out.println(this.girlName+"获得镜子");
}
}else {
synchronized (mirror){ //获得口红的锁
System.out.println(this.girlName+"获得镜子");
Thread.sleep(1000);
}
synchronized (lisptick){
System.out.println(this.girlName+"获得口红");
}
}
}
}
2.使用lock (买票问题)
package com.yyb.demo5;
import java.util.concurrent.locks.ReentrantLock;
//测试lock锁
public class TestLock {
public static void main(String[] args) {
TestLock2 testLock2 = new TestLock2();
new Thread(testLock2).start();
new Thread(testLock2).start();
new Thread(testLock2).start();
}
}
class TestLock2 implements Runnable {
private int ticketNum = 10;
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
lock.lock(); //加锁
if (ticketNum > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ticketNum--);
} else {
break;
}
} finally {
lock.unlock(); //解锁
}
}
}
}
两大实例
1.管程法(生产者消费者问题)
package com.yyb.demo6;
//生产者消费者
public class TestPC {
public static void main(String[] args) {
SynContainer container = new SynContainer();
new Productor(container).start();
new Consumer(container).start();
}
}
//生产者
class Productor extends Thread {
SynContainer container;
public Productor(SynContainer container) {
this.container = container;
}
//生产
@Override
public void run() {
for (int i = 0; i < 100; i++) {
container.push(new Chicken(i));
System.out.println("生产了" + i + "只鸡");
}
}
}
//消费者
class Consumer extends Thread {
SynContainer container;
public Consumer(SynContainer container) {
this.container = container;
}
//消费
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("消费了" + container.pop().id + "只鸡");
}
}
}
//产品
class Chicken {
int id;
Chicken(int id) {
this.id = id;
}
}
//缓冲区
class SynContainer {
Chicken[] chickens = new Chicken[10];
private int count = 0;
//生产者放入产品
public synchronized void push(Chicken chicken) {
//如果容器满了就需要等待消费
if (count == chickens.length) {
//通知消费
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
chickens[count] = chicken;
count++;
//可以通知消费者消费了
this.notifyAll();
}
public synchronized Chicken pop() {
if (count == 0) {
//等待生产
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果可以消费
count--;
Chicken chicken = chickens[count];
this.notifyAll();
return chicken;
}
}
2.信号灯(演员观众问题)
package com.yyb.demo6;
//信号灯方法
public class TestPC2 {
public static void main(String[] args) {
TV tv = new TV();
new Player(tv).start();
new Watcher(tv).start();
}
}
//生产者 演员
class Player extends Thread {
TV tv;
public Player(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if (i % 2 == 0) {
this.tv.play("快乐大本营");
} else {
this.tv.play("抖音");
}
}
}
}
//消费者 观众
class Watcher extends Thread {
TV tv;
public Watcher(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
this.tv.watch();
}
}
}
//产品 节目
class TV {
//演员表演观众等待
//观众观看演员等待
String voice;
boolean flag = true;
//表演
public synchronized void play(String voice) {
if (!flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("演员表演" + voice);
this.notifyAll();//唤醒
this.voice = voice;
this.flag = !this.flag;
}
//观看
public synchronized void watch() {
if (flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("观众观看" + voice);
this.notifyAll();
this.flag = !this.flag;
}
}