java多线程
Process与Thread
- 程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态概念。
- 进程是执行程序的一次执行过程,他是一个动态的概念。是系统资源分配的单位。
- 通常一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然,没有存在的意义。线程是CPU调度和执行的单位。
注意:很多线程是模拟出来的,真正的多线程是指有很多个CPU,即多核,如服务器。如果是模拟出来的多线程,即在一个CPU的情况下,在同一个时间点,CPU只能执行一个代码,因为切换的很快,所以就有同时执行的错觉。
线程的创建
继承Thread类
- 自定义线程类继承Thread类
- 重写run()方法,编写线程执行体
- 创建线程对象,调用start()方法启动线程
public class TestThread extends Thread {
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 20; i++) {
System.out.println("run---" + i);
}
}
public static void main(String[] args) {
//创建一个线程对象
TestThread testThread = new TestThread();
//调用start()方法开启线程
testThread.start();
//main线程,主线程
for (int i = 0; i < 20; i++) {
System.out.println("main---" + i);
}
}
}
不建议使用,避免OOP单继承局限性
实现Runnable接口
- 自定义类实现Runnable接口
- 实现run()方法,编写线程执行体
- 创建线程对象,调用start()方法启动线程
public class TestThread implements Runnable {
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 20; i++) {
System.out.println("run---" + i);
}
}
public static void main(String[] args) {
//创建runnable接口实现类对象
TestThread testThread = new TestThread();
//创建线程对象,通过线程对象来开启我们的线程,代理
Thread thread = new Thread(testThread);
thread.start();
/*new Thread(testThread).start();*/
for (int i = 0; i < 20; i++) {
System.out.println("main---" + i);
}
}
}
推荐使用,避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
模拟龟兔赛跑
//模拟龟兔赛跑
public class Race implements Runnable {
//胜利者
private static String winner;
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
//模拟兔子休息
if (Thread.currentThread().getName().equals("兔子") && i % 10 == 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//判断比赛是否结束
boolean flag = gameOver(i);
if (flag) {
break;
}
System.out.println(Thread.currentThread().getName() + "-->跑了" + i + "步");
}
}
//判断是否完成比赛
private boolean gameOver(int step) {
if (winner != null) {
return true;
} else {
if (step >= 100) {
winner = Thread.currentThread().getName();
System.out.println("winner is " + winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race, "兔子").start();
new Thread(race, "乌龟").start();
}
}
实现Callable接口
import java.util.concurrent.*;
public class TestCallable implements Callable<String> {
String name;
public TestCallable(String name) {
this.name = name;
}
@Override
public String call() throws Exception {
return name;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable t1 = new TestCallable("t1");
TestCallable t2 = new TestCallable("t2");
TestCallable t3 = new TestCallable("t3");
//创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(1);
//提交执行
Future<String> r1 = ser.submit(t1);
Future<String> r2 = ser.submit(t2);
Future<String> r3 = ser.submit(t3);
//获取结果
String res1 = r1.get();
String res2 = r2.get();
String res3 = r3.get();
System.out.println(res1);
System.out.println(res2);
System.out.println(res3);
//关闭服务
ser.shutdown();
}
}
静态代理
静态代理模式:
真实对象和代理对象都要事先同一个接口
代理对象要代理真实角色
好处:
代理对象可以做很多真实对象做不了的事情
真实对象专注做自己的事情
下面模拟结婚为例,婚庆公司为代理对象
public class StaticProxy {
public static void main(String[] args) {
WeddingCompany weddingCompany = new WeddingCompany(new You());
weddingCompany.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() {
System.out.println("before:布置现场");
this.target.HappyMarry();
System.out.println("after:收尾款");
}
}
Lambda表达式
-
λ希腊字母表中排序第是一位的字母,英文名称为Lambda
-
避免匿名内部类定义过多
-
其实质属于函数式编程的概念
(params) -> expression[表达式]
(params) -> statement [语句]
(params) ->
new Thread(()-> System.out.println("Lambda表达式")).start();
-
函数式解接口的定义:
-
任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口。
-
对于函数式接口,我们可以通过Lambda表达式来创建该接口的对象
-
/**
* 推导Lambda表达式
*/
public class TestLambda {
//3.静态内部类
static class Like2 implements ILike {
@Override
public void lambda() {
System.out.println("I Like Lambda2!");
}
}
public static void main(String[] args) {
ILike like = new Like();
like.lambda();
like = new Like2();
like.lambda();
//4.局部内部类
class Like3 implements ILike {
@Override
public void lambda() {
System.out.println("I Like Lambda3!");
}
}
like = new Like3();
like.lambda();
//5.匿名内部类
like = new ILike() {
@Override
public void lambda() {
System.out.println("I Like Lambda4!");
}
};
like.lambda();
//6.Lambda表达式,参数只有一个可以去除小括号,代码语句只有一条可以去除花括号
like = () -> {
System.out.println("I Like Lambda5!");
};
like.lambda();
}
}
//1.定义一个函数式接口
interface ILike {
void lambda();
}
//2.实现类
class Like implements ILike {
@Override
public void lambda() {
System.out.println("I Like Lambda!");
}
}
线程
线程状态


线程方法
| 方法 | 说明 |
|---|---|
| setPriority(int newPriority) | 更改线程的优先级 |
| static void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠 |
| void join() | 等待该线程终止 |
| static void yield() | 暂停当前正在执行的线程对象,并执行其他线程 |
| void interrupt() | 中断线程,别用这个方式 |
| boolean isAlive() | 测试线程是否处于活动状态 |
停止线程
- 不推荐使用JDK提供的stop()、destroy()方法
[已废弃] - 推荐线程自己停止下来
- 建议使用一个标志位进行终止变量当flag=false,则终止线程运行
public class TestStop implements Runnable {
private boolean flag = true;
@Override
public void run() {
while (flag) {
System.out.println("run... Thread");
}
}
public void stop() {
this.flag = false;
}
public static void main(String[] args) {
TestStop testStop = new TestStop();
new Thread(testStop).start();
for (int i = 0; i < 902; i++) {
System.out.println("main" + i);
if (i == 900) {
testStop.stop();
System.out.println("线程该停止了!");
}
}
}
}
线程休眠
-
sleep(时间)指定当前线程阻塞的毫秒数
-
sleep存在异常InterruptedException
-
sleep时间达到后线程进入就绪状态
-
sleep可以模拟网络延时,倒计时等
-
每个对象都有一个锁,sleep不会释放锁
//买票 public class BuyTick implements Runnable { //票数 private int ticketNums = 10; @Override public void run() { while (true) { if(ticketNums <= 0){ break; } //模拟延时:放大问题的发生性 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " --> 拿到了第" + ticketNums-- + "票"); } } public static void main(String[] args) { BuyTick ticket = new BuyTick(); new Thread(ticket,"小明").start(); new Thread(ticket,"老师").start(); new Thread(ticket,"黄牛党").start(); } } //当前是线程不安全的import java.text.SimpleDateFormat; import java.util.Date; public class TestSleep { public static void main(String[] args) throws InterruptedException { //tenDown(); //打印当前系统时间 Date startTime = new Date(System.currentTimeMillis());//获取当前系统时间 while (true){ Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime)); startTime = new Date(System.currentTimeMillis());//更新当前时间 } } public static void tenDown() throws InterruptedException {//模拟倒计时 int num = 10; while (true){ Thread.sleep(1000); System.out.println(num--); if(num <= 0){ break; } } } }
线程礼让
- 礼让线程,让当前正在执行的线程暂停,但不阻塞
- 将线程从运行状态转化为就绪状态
- 让CPU重新调度,礼让不一定成功!看CPU心情
public class TestYield {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield, "线程1").start();
new Thread(myYield, "线程2").start();
}
}
class MyYield implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "start");
Thread.yield();//线程礼让
System.out.println(Thread.currentThread().getName() + "end");
}
}
线程的强制执行
- Join合并线程,带此线程执行完成后,再次执行其他线程,其他线程阻塞
- 可以想象成插队
public class TestJoin implements Runnable {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("线程VIP来了 " + i);
}
}
public static void main(String[] args) throws InterruptedException {
//启动我们的线程
TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
//主线程
for (int i = 0; i < 205; i++) {
if (i == 200) {
thread.join();
}
System.out.println("main " + i);
}
}
}
线程的状态获取
Thread thread = new Thread();
//观察状态
Thread.State state = thread.getState();
System.out.println(state);//NEW
thread.start();//启动线程
state = thread.getState();
System.out.println(state);//RUNNABLE
while(state != Thread.State.TERMINATED){//只要线程不终止就一直输出状态
Thread.sleep(100);
state = thread.getState();//更新状态
System.out.println(state);//输出状态
}
线程的优先级
- Java提供一个线程调度器来监控程序启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行
- 线程的优先级用数字表示,范围从1~10.
- Thread.MIN_PRIORITY = 1;
- Thread.MAX_PRIORITY = 10;
- Thread.NORM_PRIORITY = 5;
- 使用getPriority()/setPriority(int xxx)方法获取或改变优先级
注意先设置优先级在启动!
优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调用了,这都是看CPU的调度
守护线程
- 线程分为用户线程和守护线程
- 虚拟机必须确保用户线程执行完毕
- 虚拟机不用等待守护线程执行完毕
- 如后台记录操作日志、监控内存、垃圾回收等待
public class TestDaemon {
public static void main(String[] args) {
God god = new God();
Me me = new Me();
Thread thread = new Thread(god);
thread.setDaemon(true);//默认是false表示是用户线程,正常的线程都是用户线程
thread.start();//上帝守护线程启动
new Thread(me).start();//用户线程启动了
}
}
class God implements Runnable{
@Override
public void run() {
while (true){
System.out.println("上帝保佑着你!");
}
}
}
class Me implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("我一生都开心的活着");
}
System.out.println("============goodbye!world!");
}
}
线程同步
- 并发:同一个对象被多个线程 同时操作
- 形成条件: 队列和锁
- synchronized
同步方法及同步代码块
同步方法
//买票
public class BuyTick {
public static void main(String[] args) {
Buy ticket = new Buy();
new Thread(ticket, "小明").start();
new Thread(ticket, "黄牛党").start();
}
}
class Buy implements Runnable{
//票数
private int ticketNums = 100;
private boolean flag = true;//外部停止方式
@Override
public void run() {
while (flag) {
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//synchronized同步方法,锁的是this
private synchronized void buy() throws InterruptedException {
//判断是否还有票
if (ticketNums <= 0) {
flag = false;
}
//买票
System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--);
}
}
同步代码块
//买票
public class BuyTick {
public static void main(String[] args) {
Buy ticket = new Buy();
new Thread(ticket, "小明").start();
new Thread(ticket, "黄牛党").start();
}
}
class Buy implements Runnable {
//票数
private int ticketNums = 100;
private boolean flag = true;//外部停止方式
@Override
public void run() {
//同步代码块
synchronized (this) {
while (flag) {
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private void buy() throws InterruptedException {
//判断是否还有票
if (ticketNums <= 0) {
flag = false;
}
//买票
System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--);
}
}
CopyOnWriteArrayList
import java.util.concurrent.CopyOnWriteArrayList;
public class TestJUC {
public static void main(String[] args) throws InterruptedException {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
for (int i = 0; i < 10000; i++) {
new Thread(() -> {
list.add(Thread.currentThread().getName());
}).start();
}
Thread.sleep(3000);
System.out.println(list.size());
}
}
死锁
两个线程抢同一个进程,比如一双筷子,你拿了一只,他拿了一只,都在等在对方把剩下哪只给过来,不过谁都不愿意给谁。
public class DeadLock {
public static void main(String[] args) {
Makeup girl1 = new Makeup(0,"灰姑娘");
Makeup girl2 = new Makeup(1,"白雪公主");
girl1.start();
girl2.start();
}
}
//口红
class Lipstick {
}
//镜子
class Mirror {
}
class Makeup extends Thread {
//需要的资源,只有一份,用static保证只有一份
static Lipstick lipstick = new Lipstick();
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 (lipstick){//获得口红的锁
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(2000);
synchronized (lipstick){//一秒钟后想获得口红的锁
System.out.println(this.girlName + "获得口红的锁!");
}
}
}
}
}
Lock锁
import javax.sound.midi.Soundbank;
import java.util.concurrent.locks.ReentrantLock;
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 {
int ticketNums = 10;
//定义lock锁
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
lock.lock();//加锁
if (ticketNums > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ticketNums--);
} else {
break;
}
} finally {
lock.unlock();//解锁
}
}
}
}
线程协作
| 方法名 | 作用 |
|---|---|
| wait() | 表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁 |
| wait(long timeout) | 指定等待的毫秒数 |
| notify() | 唤醒一个处于等待状态的下线程 |
| notifyAll() | 唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度 |
均是Object类的方法,都只能在同步方法或同步代码块中使用,否者会抛出异常
管程法
//测试:生产者消费者模型 --> 利用缓冲区解决 : 管程法
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 Item(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 Item {
int id;//产品编号
public Item(int id) {
this.id = id;
}
}
//缓冲区
class SynContainer {
//需要一个容器大小
Item[] items = new Item[10];
int count = 0;
//生产者放入产品
public synchronized void push(Item item) {
//如果容器满了,就需要等待消费者消费
if (count == items.length) {
//通知消费者消费,生产等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//否者丢入产品
items[count] = item;
count++;
//通知消费者消费
this.notifyAll();
}
//消费者消费产品
public synchronized Item pop() {
//如果容器满了,就需要等待消费者消费
if (count == 0) {
//等待生产者生产,消费者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//否者可以消费
count--;
Item item = items[count];
//吃完了,通知生产者生产
this.notifyAll();
return item;
}
}
信号灯法
//信号灯法,标志位解决
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++) {
tv.watch();
}
}
}
//产品-->节目
class Tv{
//演员表演,观众等待 T
//观众观看,演员等待 F
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;
}
}
线程池
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//测试线程池
public class TestPool {
public static void main(String[] args) {
//1.创建服务,创建线程池
//newFixedThreadPool 参数为:线程池大小
ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//2.关闭连接
service.shutdown();
}
}
class MyThread implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}

浙公网安备 33010602011771号