Java多线程学习笔记
概念
进程是程序的一次执行过程
是系统资源分配的单位
main()称为主线程,为系统入口
进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程
线程是指进程中的一个执行流程,一个进程中可以运行多个线程
线程的状态
创建方式
-
继承Thread类
-
重写run方法,调用start开启线程
-
存在单继承的局限性
-
package CreadThread; public class TestThread1 extends Thread{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(0); } } public static void main(String[] args) { TestThread1 testThread1 = new TestThread1(); testThread1.start(); for (int i = 0; i < 100; i++) { System.out.println(1); } } }
-
-
实现Runnable接口
-
重写run方法,通过创建线程对象来启动自己的线程
-
灵活方便,方便同一个对象被多个线程使用
-
package CreadThread; public class TestThread2 implements Runnable { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(0); } } public static void main(String[] args) { //创建Runnable接口的实现类 TestThread2 testThread2 = new TestThread2(); // Thread thread = new Thread(testThread2); // thread.start(); //创建线程对象,通过线程来开启我们的线程,静态代理 new Thread(testThread2).start(); for (int i = 0; i < 100; i++) { System.out.println(1); } } }
-
-
实现Callable接口
-
重写call方法;创建目标对象;执行服务newFixedTreadPool;提交执行submit;获取结果get;关闭服务shutdownNow
-
可以抛出异常
-
package CreadThread.testCallable; import CreadThread.TestThread12; import java.util.concurrent.*; public class TestCallable implements Callable { private int n = 10; @Override public Boolean call(){ while (true){ if (n<=0){ break; } System.out.println(Thread.currentThread().getName()+"标志减一======"+n--); } return true; } public static void main(String[] args) throws ExecutionException, InterruptedException { TestCallable t1 = new TestCallable(); TestCallable t2 = new TestCallable(); TestCallable t3 = new TestCallable(); //创建服务 ExecutorService ser = Executors.newFixedThreadPool(3); //提交服务 Future<Boolean> result1 = ser.submit(t1); Future<Boolean> result2 = ser.submit(t2); Future<Boolean> result3 = ser.submit(t3); //获取结果 boolean r1 = result1.get(); boolean r2 = result1.get(); boolean r3 = result1.get(); //关闭服务 ser.shutdownNow(); } }
-
多个线程操控同一个对象
案例1
package CreadThread;
public class TestThread12 implements Runnable{
private int n = 10;
@Override
public void run() {
while (true){
if (n<=0){
break;
}
System.out.println(Thread.currentThread().getName()+"标志减一======"+n--);
}
}
public static void main(String[] args) {
TestThread12 testThread12 = new TestThread12();
new Thread(testThread12,"a").start();
new Thread(testThread12,"b").start();
new Thread(testThread12,"c").start();
/**
* c标志减一======10
* c标志减一======9
* c标志减一======8
* c标志减一======7
* c标志减一======6
* a标志减一======10
* a标志减一======4
* b标志减一======10
* b标志减一======2
* b标志减一======1
* a标志减一======3
* c标志减一======5
* 多个线程操控同一个对象时出现了线程不安全问题
* 出现线程不安全的问题
*/
}
}
案例2
package CreadThread;
public class TestThread3 implements Runnable{
private static String u;
@Override
public void run() {
for (int i = 0; i <= 10000; i++) {
if (Thread.currentThread().getName().equals("a")){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (over(i)){
break;
}
System.out.println(Thread.currentThread().getName()+"===="+i);
}
}
private boolean over(int s){
if (u!=null){
return true;
}else {
if (s >= 10000){
u = Thread.currentThread().getName();
System.out.println(u+"=="+s+"==结束");
return true;
}
}
return false;
}
public static void main(String[] args) {
TestThread3 testThread3 = new TestThread3();
new Thread(testThread3,"a").start();
new Thread(testThread3,"b").start();
}
}
/**
i=10时,且a未睡眠
a====0
a====1
a====2
a====3
a====4
a====5
a====6
b====0
a====7
a====8
a====9
a==10==结束
b====1
**/
模拟静态代理
案例:
- 小明:真实角色
- 婚庆公司:代理小明,帮他处理结婚的事
- 结婚:都是实现结婚接口
package staticThread;
public class StaticProxy {
public static void main(String[] args) {
XiaoMing xiaoMing = new XiaoMing();
new Thread(()->System.out.println("启动")).start();
//对比
new WeddingCompany(new XiaoMing()).HappyMarry();
// WeddingCompany weddingCompany = new WeddingCompany(xiaoMing);
// weddingCompany.HappyMarry();
}
}
interface Marry{
void HappyMarry();
}
class XiaoMing implements Marry{
@Override
public void HappyMarry() {
System.out.println("小明===结婚");
}
}
class WeddingCompany implements Marry{
private Marry target;
public WeddingCompany() {
}
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void HappyMarry() {
before();
this.target.HappyMarry();
after();
}
private void before(){
System.out.println("结婚之前");
}
private void after(){
System.out.println("结婚之后");
}
}
/**
代理对象和真实对象需实现同一接口
代理对象可以完成真实对象做不了的其他事情
真实对象只需要关注自己的事情
**/
Lambda表达式
- 避免内部类定义过多
- 其实质属于函数式编程的理念
函数式接口
- 任何接口,如果只包含唯一一个抽象方法,那么它就是函数式接口
- 对于函数式接口,可以通过lambda表达式接口的对象
案例:
package lamda;
public class TestLambda {
//静态内部类
static class L2 implements IL{
@Override
public void lambda() {
System.out.println("L2静态内部类");
}
}
public static void main(String[] args) {
IL il = new L1();
il.lambda();
IL il2 = new L2();
il2.lambda();
//局部内部类
class L3 implements IL{
@Override
public void lambda() {
System.out.println("L3局部内部类");
}
}
IL il3 = new L3();
il3.lambda();
//匿名内部类
IL il4 = new IL() {
@Override
public void lambda() {
System.out.println("L4匿名内部类");
}
};
il4.lambda();
//lambda简化
IL il5 = ()->{
System.out.println("L5 lambda简化");
};
il5.lambda();
/**
简化
il = (int a)->{
System.out.println();
}
il = (a)->{
System.out.println();
}
il = a->{
System.out.println();
}
il = a->System.out.println();
**/
}
}
interface IL{
void lambda();
}
class L1 implements IL{
@Override
public void lambda() {
System.out.println("L1");
}
}
停止线程
- Thread的stop方法(不建议)
- 推荐线程自己停下来
- 建议使用一个标志位进行终止变量,当flag=false,则终止线程运行
package StopThread;
public class TestStop implements Runnable{
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag){
System.out.println("run==="+i++);
}
}
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 < 100; i++) {
System.out.println("main"+i);
if (i==90){
testStop.stop();
System.out.println("结束");
}
}
}
}
线程休眠
- sleep(时间),当前线程阻塞的毫秒数
- 可以模拟网络延时(放大问题的发生性)
- 每个对象都有一个锁,sleep不会释放锁
package StopThread;
public class TestSleep implements Runnable{
private int n = 10;
@Override
public void run() {
while (true){
if (n<=0){
break;
}
//模拟延时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"标志减一======"+n--);
}
}
public static void main(String[] args) {
TestSleep testThread12 = new TestSleep();
new Thread(testThread12, "a").start();
new Thread(testThread12, "b").start();
new Thread(testThread12, "c").start();
}
}
计时
Date startTime = new Date(System.currentTimeMillis());//系统当前时间
while (true){
try {
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
startTime = new Date(System.currentTimeMillis());//更新当前时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
11:15:46
11:15:47
11:15:48
11:15:49
11:15:50
11:15:51
11:15:52
11:15:53
**/
线程礼让
- 礼让线程,让当前正在执行的线程暂停,但不阻塞
- 运行转就绪
- 礼让不一定成功
package StopThread;
public class TestYield {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield,"a").start();
new Thread(myYield,"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始");
Thread.yield();//礼让
System.out.println(Thread.currentThread().getName()+"停止");
}
}
/**
* 礼让成功
b开始
a开始
b停止
a停止
礼让不成功
b开始
b停止
a开始
a停止
**/
线程强制执行 join
- Join合并线程,待此线程执行完毕后,再执行其他线程,其他线程阻塞
- 插队
package StopThread;
public class TestJoin implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("线程 "+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 < 100; i++) {
if(i==20){
thread.join();
}
System.out.println("main "+i);
}
}
}
线程状态观测
Thread.State
- NEW:还未启动
- RUNNABLE:正在jvm中运行,但是可能正在等待操作系统的其他资源
- BLOCKED:受阻塞,并且正在等待监视器锁
- WAITING:处于等待状态的线程,正在等待另一个线程执行特定的操作
- TERMINATED:结束
- TIMED_WAITING:限期等待,将在特定的时间内自行返回
package StopThread;
public class TestState{
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("===");
});
Thread.State state = thread.getState();
System.out.println(state);
thread.start();
state = thread.getState();
System.out.println(state);
while (state!= Thread.State.TERMINATED){
Thread.sleep(100);
state = thread.getState();
System.out.println(state);
}
}
}
线程优先级
-
范围1~10:Thread.MIN_PRIORITY = 1;
Thread.MAX_PRIORITY = 10;
Thread.NORM_PRIORITY = 5
-
线程默认优先级是 5;
-
优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调用了,这都是看CPU的调度
-
getPriority .setPriority()
package StopThread;
public class TestPriority {
public static void main(String[] args) {
//主线程优先级
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
MyPrioirty myPrioirty = new MyPrioirty();
Thread t1 = new Thread(myPrioirty);
Thread t2 = new Thread(myPrioirty);
Thread t3 = new Thread(myPrioirty);
Thread t4 = new Thread(myPrioirty);
Thread t5 = new Thread(myPrioirty);
Thread t6 = new Thread(myPrioirty);
//在启动前设置优先级
t1.start();
t2.setPriority(1);
t2.start();
t3.setPriority(4);
t3.start();
t4.setPriority(Thread.MAX_PRIORITY);
t4.start();
// t5.setPriority(-1);
// t5.start();
//
// t6.setPriority(11);
// t6.start();
}
}
class MyPrioirty implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
}
}
/**
main-->5
Thread-0-->5
Thread-3-->10
Thread-2-->4
Thread-1-->1
**/
守护线程
- 在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程)
- 守护线程(列如:main):为所有非守护线程提供服务的线程;换句话说,任何一个守护线程都是整个JVM中所有非守护线程的保姆
- 虚拟机必须确保用户线程执行完毕,不用等待守护线程执行完毕
- 后台记录日志,监控内存,垃圾回收
public class TestDaemon {
public static void main(String[] args) {
Y y = new Y();
X x = new X();
Thread thread = new Thread(y);
thread.setDaemon(true);//默认false,表示用户线程
thread.start();//守护线程启动
new Thread(x).start();//用户线程启动
}
}
class X implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("存在 "+i);
}
System.out.println("结束");
}
}
class Y implements Runnable{
@Override
public void run() {
while (true){
System.out.println("Y 存在 ");
}
}
}
/**
* Y 存在
* Y 存在
* 存在 3
* 存在 4
* 存在 5
* 存在 6
* 存在 7
* 存在 8
* 存在 9
* 结束
* Y 存在
* Y 存在
不必等待守护线程的结束
**/
线程同步
-
synchronized
-
同步是一种高开销的操作,因此应该尽量减少同步的内容
-
同步块:synchronized(Obj){},Obj称为同步监视器
-
同步块是通过锁定一个指定的对象,来对同步块中包含的代码进行同步
synchronized(){ .... }
-
/** * 线程同步的运用 * */ public class SynchronizedThread { class Bank { private int account = 100; public int getAccount() { return account; } /** * 用同步方法实现 * * @param money */ public synchronized void save(int money) { account += money; } /** * 用同步代码块实现 * * @param money */ public void save1(int money) { synchronized (this) { account += money; } } } class NewThread implements Runnable { private Bank bank; public NewThread(Bank bank) { this.bank = bank; } @Override public void run() { for (int i = 0; i < 10; i++) { // bank.save1(10); bank.save(10); System.out.println(i + "账户余额为:" + bank.getAccount()); } } } /** * 建立线程,调用内部类 */ public void useThread() { Bank bank = new Bank(); NewThread new_thread = new NewThread(bank); System.out.println("线程1"); Thread thread1 = new Thread(new_thread); thread1.start(); System.out.println("线程2"); Thread thread2 = new Thread(new_thread); thread2.start(); } public static void main(String[] args) { SynchronizedThread st = new SynchronizedThread(); st.useThread(); } }
-
-
同步方法:给方法加关键字synchronized
package syn;
public class UnsafeBuyTicket {
public static void main(String[] args) {
BuyTicket station = new BuyTicket();
new Thread(station,"a").start();
new Thread(station,"b").start();
new Thread(station,"b").start();
}
}
class BuyTicket implements Runnable{
private int tNums = 10;
boolean flag = true;
@Override
public void run() {
//买票
while (flag){
buy();
}
}
//同步方法,锁的值是this
private synchronized void buy(){
//是否有票
if (tNums<=0){
flag = false;
return;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"Buy "+tNums--);
}
}
/**
不安全时:bBuy 10
bBuy 10
aBuy 9
bBuy 8
aBuy 6
bBuy 7
bBuy 5
bBuy 4
aBuy 5
bBuy 2
aBuy 1
bBuy 3
安全时:
aBuy 10
aBuy 9
aBuy 8
aBuy 7
aBuy 6
aBuy 5
aBuy 4
aBuy 3
aBuy 2
aBuy 1
**/
死锁
- 所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进
- 多个线程相互有着对方需要的资源,然后形成僵持
- 产生死锁的必要条件
- 互斥条件:一个资源每次只能被一个进程使用
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
- 不可剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
public class Deadlock {
}
class L{
public static void main(String[] args) {
Ma ma1 = new Ma(0,"a1");
Ma ma2 = new Ma(0,"a2");
ma1.start();
ma2.start();
}
}
class M{
}
class Ma extends Thread{
//保证需要的资源只有一份
static L l = new L();
static M m = new M();
int choice;
String people;
Ma(int choice,String people){
this.choice = choice;
this.people = people;
}
Ma(){
}
@Override
public void run() {
try {
mup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void mup() throws InterruptedException {
if (choice==0){
synchronized (l){
System.out.println(this.people+"获得锁1");
Thread.sleep(1000);
synchronized (m){
System.out.println(this.people+"获得锁2");
}
}
}else {
synchronized (m){
System.out.println(this.people+"获得锁2");
Thread.sleep(2000);
synchronized (l){
System.out.println(this.people+"获得锁1");
}
}
}
}
}
/**
synchronized (l){
System.out.println(this.people+"获得锁1");
Thread.sleep(1000);
}
synchronized (m){
System.out.println(this.people+"获得锁2");
}
**/
Lock(锁)
- Lock是显示锁,synchronized是隐式锁,出了作用域自动释放
- Lock只有代码锁
- Lock锁JVM花费较少的实践来调度线程,性能更好。并且具有更好的拓展性
package lock;
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 tNums = 10;
//定义LOck
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
lock.lock();//加锁
if (tNums>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(tNums--);
}else {
break;
}
}finally {
//解锁
lock.unlock();
}
}
}
}
/**
10
9
8
7
6
5
4
3
2
1
**/
线程协作
Object的方法:
方法名 | 作用 |
---|---|
wait() | 表示线程一直等待,直到其他线程通知,会释放锁 |
wait(long timeout) | 指定等待毫秒数 |
notify() | 唤醒一个处于等待状态的线程 |
notifyAll() | 唤醒同一个对象所有调用wait()方法的线程,优先级别高的线程优先调度 |
生产者消费者案例(利用缓冲区)
package lock;
import javax.security.auth.login.CredentialNotFoundException;
//利用缓存区解决
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+"只");
container.pop();
}
}
}
class Chicken{
int id;
public Chicken(int id) {
this.id = id;
}
}
//缓冲区
class SynContainer{
//容器
Chicken[] chickens = new Chicken[10];
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++;
System.out.println("生产"+chicken.id+"只");
//可以通知消费者消费
this.notifyAll();
}
//消费
public synchronized Chicken pop(){
//能否消费
if (count==0){
//通知生产者等生产
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//消费者消费
count--;
Chicken chicken = chickens[count];
System.out.println("消费了第"+chicken.id+"只");
//通知生产者生产
this.notifyAll();
return chicken;
}
}
还有信号量法
线程池
- 线程池线程池就是首先创建一些线程,它们的集合称为线程池,使用线程池可以很好的提高性能,线程池在系统启动时既创建大量空闲的线程,程序将一个任务传给线程池
- ExecutorService线程池接口
- Executors:工具类,线程池的工厂类,创建并返回不同类型的线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestPool {
public static void main(String[] args) {
//创建线程池
ExecutorService service = Executors.newFixedThreadPool(10);//大小为10
//执行
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//关闭链接
service.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
/**
pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
pool-1-thread-4
**/
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//消费者消费
count–;
Chicken chicken = chickens[count];
System.out.println(“消费了第”+chicken.id+“只”);
//通知生产者生产
this.notifyAll();
return chicken;
}
}
还有信号量法
## 线程池
- 线程池线程池就是首先创建一些线程,它们的集合称为线程池,使用线程池可以很好的提高性能,线程池在系统启动时既创建大量空闲的线程,程序将一个任务传给线程池
- ExecutorService线程池接口
- Executors:工具类,线程池的工厂类,创建并返回不同类型的线程池
```java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestPool {
public static void main(String[] args) {
//创建线程池
ExecutorService service = Executors.newFixedThreadPool(10);//大小为10
//执行
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//关闭链接
service.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
/**
pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
pool-1-thread-4
**/