程序人生,一文学会多线程(1)

@Override

public void run() {

while(true){

if(ticket>0){

System.out.println(Thread.currentThread().getName()+“卖票”+ticket);

ticket–;

} else {

break;

}

}

}

}

public class RunnableTest {

public static void main(String[] args) {

Run run=new Run();

Thread thread1 = new Thread(run);

Thread thread2 = new Thread(run);

Thread thread3 = new Thread(run);

thread1.start();

thread2.start();

thread3.start();

}

}

class Run implements Runnable{

private int ticket=100;//这里不用加static

@Override

public void run() {

while(true){

if(ticket>0){

System.out.println(Thread.currentThread().getName()+“卖票”+ticket);

ticket–;

}else {

break;

}

}

}

}

多线程创建两种方式的比较


开发中:优先选择实现Runnable接口的方式

  1. 实现的方式没有单继承的局限性

  2. 实现的方式更适合来处理多个线程共享数据

联系:Thread继承了Runnable接口

相同点:都需要重写run方法,将线程执行的逻辑写在run方法中

JDK5.0新增线程创建方式


实现Callable接口

  • 相比Runnable,可以有返回值

  • 方法可以抛出异常

  • 支持泛型的返回值

  • 需要借助FutureTask类,比如获取返回结果

创建线程的方式三:

  1. 创建一个实现callable的接口

  2. 实现call方法,将此线程需要执行的操作声明在call()中

  3. 创建callable接口实现类的对象

  4. 将此callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象

  5. 将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象并调用start方法

  6. 获取callable中call方法的返回值

public class CallableTest {

public static void main(String[] args) {

ThreadTests t = new ThreadTests();

FutureTask futureTask1 = new FutureTask(t);

new Thread(futureTask1).start();

try {

Object sum = futureTask1.get();

System.out.println(“总合”+sum);

}catch (Exception e){

e.printStackTrace();

}

}

}

class ThreadTests implements Callable{

@Override

public Object call() throws Exception {

int num=0;

for (int i = 0; i <= 100; i++) {

if (i % 2 == 0){

System.out.println(i);

num += i;

}

}

return num;

}

}

线程池创建线程


优点:

  • 提高响应速度(减少了创建新线程的时间)

  • 降低资源消耗(重复利用线程池中线程,不需要每次都创建)

  • 便于线程管理

public class ThreadPool {

public static void main(String[] args) {

ExecutorService service = Executors.newFixedThreadPool(10);

service.execute(new NumberThreadTest());//适合Runnable接口

service.execute(new NumberThreadTest());

//service.submit()适合使用和callable

service.shutdown();//关闭线程池

}

}

class NumberThreadTest implements Runnable{

private static int ticket=100;

@Override

public void run() {

while(true){

if (ticket>0){

System.out.println(Thread.currentThread().getName()+“:”+ticket);

ticket–;

}else {

break;

}

}

}

}

线程常用方法


yield();//释放当前cpu的执行权

join();//在线程a中调用线程b的join方法,线程a会陷入阻塞状态直到线程b执行完毕

stop();//强制线程生命期结束,不推荐使用

boolean isAlive();//判断线程是否还或者

sleep(long timemilltime);//让当前线程睡眠指定的milltime毫秒,在指定的milltime毫秒时间内,当前线程是阻塞状态

**以下三个方法必须在同步代码块或者同步方法中使用,并且调用者必须是同步代码块或同步方法中的同步监视器(同一把锁)**否则会出现IllegalMonitorStateException异常

属于Object类中的方法

wait():一旦执行此方法,当前线程进入阻塞状态,并释放同步监视器

notify():一旦执行此方法,就会唤醒被wait的一个线程,如果有多个线程被wait,则唤醒优先级高的

notifyAll():唤醒所有线程

线程的优先级


MAX_PRIORITY:10

MIN_PRIORITY:1

NORM_PRIORITY:5

默认优先级都为5

如何获取:

  1. getPriority():获取线程的优先级

  2. setPriority(int p):设置线程的优先级

并不是优先级高就一定先被CPU执行,只能从概率上讲更容易被CPU执行

线程的生命周期


  1. 新建

  2. 就绪

  3. 运行

  4. 阻塞

  5. 死亡

synchronized


操作共享数据的代码,即为需要被同步的代码

  • 共享数据:多个线程共同操作的变量

  • 同步监视器:锁

  • 任何一个类的对象都可以充当锁

  • 多个线程必须用同一把锁

synchronized同步代码块解决线程安全问题

Runnable同步代码块解决线程安全的问题

/**

* 操作共享数据的代码,即为需要被同步的代码

* 共享数据:多个线程共同操作的变量

* 同步监视器:锁

* 任何一个类的对象都可以充当锁

* 多个线程必须用同一把锁

*/

public class RunnableTest {

public static void main(String[] args) {

Run run=new Run();

Thread thread1 = new Thread(run);

Thread thread2 = new Thread(run);

Thread thread3 = new Thread(run);

thread1.start();

thread2.start();

thread3.start();

}

}

class Run implements Runnable{

private  int ticket=100;

Object object=new Object();

@Override

public void run() {

while(true){

synchronized(object){//可以使用this充当锁,this为当前对象

if(ticket>0){

try {

Thread.sleep(200);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+“卖票”+ticket);

ticket–;

}else {

break;

}

}

}

}

}

执行结果

Thread-0卖票100

Thread-0卖票99

Thread-2卖票98

Thread-1卖票97

Thread-1卖票96

Thread-1卖票95

Thread-2卖票94

Thread-2卖票93

Thread-2卖票92

Thread-2卖票91

Thread-2卖票90

Thread-2卖票89

Thread-2卖票88

Thread-2卖票87

Thread-2卖票86

Thread-2卖票85

Thread-0卖票84

Thread-0卖票83

Thread-0卖票82

Thread-0卖票81

Thread-0卖票80

Thread-0卖票79

Thread-0卖票78

Thread-0卖票77

Thread-0卖票76

Thread-0卖票75

Thread-0卖票74

Thread-0卖票73

Thread-0卖票72

Thread-0卖票71

Thread-0卖票70

Thread-0卖票69

Thread-0卖票68

Thread-0卖票67

Thread-0卖票66

Thread-0卖票65

Thread-0卖票64

Thread-0卖票63

Thread-0卖票62

Thread-0卖票61

Thread-0卖票60

Thread-2卖票59

Thread-2卖票58

Thread-2卖票57

Thread-2卖票56

Thread-2卖票55

Thread-2卖票54

Thread-2卖票53

Thread-2卖票52

Thread-2卖票51

Thread-2卖票50

Thread-2卖票49

Thread-2卖票48

Thread-2卖票47

Thread-2卖票46

Thread-2卖票45

Thread-2卖票44

Thread-2卖票43

Thread-1卖票42

Thread-1卖票41

Thread-1卖票40

Thread-1卖票39

Thread-1卖票38

Thread-1卖票37

Thread-1卖票36

Thread-1卖票35

Thread-1卖票34

Thread-1卖票33

Thread-1卖票32

Thread-1卖票31

Thread-1卖票30

Thread-1卖票29

Thread-1卖票28

Thread-1卖票27

Thread-1卖票26

Thread-2卖票25

Thread-2卖票24

Thread-2卖票23

Thread-2卖票22

Thread-2卖票21

Thread-2卖票20

Thread-2卖票19

Thread-2卖票18

Thread-2卖票17

Thread-2卖票16

Thread-2卖票15

Thread-2卖票14

Thread-2卖票13

Thread-2卖票12

Thread-2卖票11

Thread-2卖票10

Thread-2卖票9

Thread-2卖票8

Thread-2卖票7

Thread-2卖票6

Thread-2卖票5

Thread-2卖票4

Thread-2卖票3

Thread-0卖票2

Thread-0卖票1

Process finished with exit code 0

同步的方式解决了线程安全的问题,操作同步代码时,只有一个线程参与,其他线程等待,相当于一个单线程的过程,效率低

Thread方式同步代码块解决线程安全的问题

public class ThreadTest {

public static void main(String[] args) {

MyThread m1 = new MyThread();

MyThread m2 = new MyThread();

MyThread m3 = new MyThread();

m1.start();

m2.start();

m3.start();

}

}

class MyThread extends Thread{

private static int ticket=100;

Object object=new Object();

@Override

public void run() {

while(true){

synchronized(object){//不可以使用this充当锁,这里this代表了m1,m2,m3三个对象

try {

sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

if(ticket > 0){

System.out.println(Thread.currentThread().getName()+“卖票:”+ticket);

ticket–;

}else {

break;

}

}

}

}

}

执行结果

Thread-0卖票:100

Thread-1卖票:100

Thread-2卖票:100

Thread-2卖票:97

Thread-1卖票:97

Thread-0卖票:97

Thread-2卖票:94

Thread-0卖票:94

Thread-1卖票:94

Thread-1卖票:91

Thread-2卖票:91

Thread-0卖票:90

Thread-2卖票:88

Thread-1卖票:88

Thread-0卖票:88

Thread-2卖票:85

Thread-0卖票:84

Thread-1卖票:84

Thread-2卖票:82

Thread-0卖票:82

Thread-1卖票:82

Thread-2卖票:79

Thread-0卖票:79

Thread-1卖票:78

Thread-2卖票:76

Thread-1卖票:76

Thread-0卖票:76

Thread-2卖票:73

Thread-1卖票:73

Thread-0卖票:73

Thread-0卖票:70

Thread-1卖票:70

Thread-2卖票:70

Thread-1卖票:67

Thread-0卖票:67

Thread-2卖票:66

Thread-2卖票:64

Thread-1卖票:64

Thread-0卖票:62

Thread-2卖票:61

Thread-1卖票:61

Thread-0卖票:61

Thread-1卖票:58

Thread-0卖票:58

Thread-2卖票:56

Thread-0卖票:55

Thread-1卖票:55

Thread-2卖票:55

Thread-0卖票:52

Thread-1卖票:52

Thread-2卖票:52

Thread-1卖票:49

Thread-2卖票:49

Thread-0卖票:49

Thread-2卖票:46

Thread-0卖票:46

Thread-1卖票:46

Thread-2卖票:43

Thread-0卖票:43

Thread-1卖票:43

Thread-2卖票:40

Thread-1卖票:40

Thread-0卖票:40

Thread-0卖票:37

Thread-2卖票:37

Thread-1卖票:37

Thread-2卖票:34

Thread-1卖票:34

Thread-0卖票:34

Thread-2卖票:31

Thread-0卖票:31

Thread-1卖票:31

Thread-1卖票:28

Thread-2卖票:28

Thread-0卖票:28

Thread-0卖票:25

Thread-2卖票:25

Thread-1卖票:25

Thread-1卖票:22

Thread-0卖票:22

Thread-2卖票:22

Thread-2卖票:19

Thread-0卖票:19

Thread-1卖票:19

Thread-2卖票:16

Thread-1卖票:16

Thread-0卖票:16

Thread-2卖票:13

Thread-0卖票:13

Thread-1卖票:13

Thread-2卖票:10

Thread-0卖票:10

Thread-1卖票:10

Thread-2卖票:7

Thread-0卖票:7

Thread-1卖票:7

Thread-2卖票:4

Thread-1卖票:4

Thread-0卖票:4

Thread-1卖票:1

Thread-2卖票:1

Thread-0卖票:1

Process finished with exit code 0

会发现还是线程不安全,这是因为三个对象使用的锁不是同一把锁了

一定要注意给object 加上static 才行

static Object object=new Object();

加入后就会发现线程又安全了

或者使用 MyThread.class 充当锁

Synchronized同步方法解决线程安全问题

使用同步方法解决线程安全问题

实现Runnable接口方式

public class SynchronizedMethod {

public static void main(String[] args) {

ThreadMethod threadMethod = new ThreadMethod();

Thread thread1 = new Thread(threadMethod);

Thread thread2 = new Thread(threadMethod);

Thread thread3 = new Thread(threadMethod);

thread1.start();

thread2.start();

thread3.start();

}

}

class ThreadMethod implements Runnable{

private  int ticket=100;

public synchronized void show(){//这里用的锁是this

try {

Thread.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

if(ticket > 0){

System.out.println(Thread.currentThread().getName()+“卖票:”+ticket);

ticket–;

}

}

@Override

public void run() {

while(ticket>0){

show();

}

}

}

继承Thread类方式

public class SynchronizedMethodThread {

public static void main(String[] args) {

ThreadMethod threadMethod1 = new ThreadMethod();

ThreadMethod threadMethod2 = new ThreadMethod();

ThreadMethod threadMethod3 = new ThreadMethod();

threadMethod1.start();

threadMethod2.start();

threadMethod3.start();

}

}

class ThreadMethod extends Thread{

private  static int ticket=100;

public static synchronized void show(){//这里必须加上static,不加上static锁使用的为this对象,这里创建了三个对象。加上static锁使用的为ThreadMethod.class

try {

Thread.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

if(ticket > 0){

System.out.println(Thread.currentThread().getName()+“卖票:”+ticket);

ticket–;

}

}

@Override

public void run() {

while(ticket>0){

show();

}

}

}

同步方法总结

  • 同步方法仍涉及到同步监视器,只是不需要我们显示的声明

  • 非静态的同步方法,同步监视器(锁)是:this

  • 静态的同步方法,同步监视器(锁)是:当前类本身

锁方式解决线程安全问题


public class ReentrantLockTest {

public static void main(String[] args) {

Window window = new Window();

Thread thread1 = new Thread(window);

Thread thread2 = new Thread(window);

Thread thread3 = new Thread(window);

thread1.start();

thread2.start();

thread3.start();

}

}

class Window implements Runnable{

private  int ticket=100;

private ReentrantLock reentrantLock=new ReentrantLock();

@Override

public void run() {

while (true){

reentrantLock.lock();//加锁

try {

if(ticket>0){

try {

Thread.sleep(50);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+“卖票”+ticket);

ticket–;

}else {

break;

}

}finally {

reentrantLock.unlock();//释放锁

}

}

}

}

注意:如果用继承Thread类的方式去使用lock

必须在 锁前面加上static

private static ReentrantLock reentrantLock=new ReentrantLock();

Synchronized和锁(Lock)方式的异同?


  • 相同:两者都可以解决线程安全问题

  • 不同:Synchronized机制在执行完相应的同步代码后,自动释放同步监视器,Lock需要手动启动同步(Lock()),同时结束也需要手动结束同步(unlock())

单例模式线程安全


class Bank{

private static Bank instance = null;

private Bank(){}

public  static  Bank  getInstance(){

//       synchronized(Bank.class){//方式一:效率稍差

//           if (instance == null){

//               instance=new Bank();

//           }

//           return instance;

//       }

//方式二:效率更高

if (instance == null){

synchronized(Bank.class){

if (instance == null){

instance=new Bank();

}

}

}

return instance;

}

}

死锁

不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁

死锁案例

public class DeadLock {

public static void main(String[] args) {

StringBuffer s1=new StringBuffer();

StringBuffer s2=new StringBuffer();

new Thread(){

@Override

public void run() {

synchronized (s1){

s1.append(“a”);

s2.append(“1”);

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized (s2){

s1.append(“b”);

s2.append(“2”);

System.out.println(s1);

System.out.println(s2);

}

}

}

}.start();

new Thread(new Runnable() {

@Override

public void run() {

synchronized (s2){

s1.append(“c”);

s2.append(“3”);

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized (s1){

s1.append(“d”);

s2.append(“4”);

System.out.println(s1);

System.out.println(s2);

}

}

}

}).start();

}

}

多线程通信列题


public class CommunicationTest {

/**

* 实现两个线程交替打印1-100

*/

public static void main(String[] args) {

Test test = new Test();

Thread t1 = new Thread(test);

Thread t2 = new Thread(test);

Thread t3 = new Thread(test);

t1.start();

t2.start();

t3.start();

}

}

class Test implements Runnable{

private int number=1;

@Override

public void run() {

while (true){//while条件不能用number <= 100 因为这样就没有全锁住操作共享数据的代码,线程就不安全了

synchronized (this){     //也不能锁住while 锁住了就只有一个线程能进来操作了

if (number <= 100){

try {

Thread.sleep(20);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+“:”+number);

number++;

}else {

break;

}

}

}

}

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

就写到这了,也算是给这段时间的面试做一个总结,查漏补缺,祝自己好运吧,也希望正在求职或者打算跳槽的 程序员看到这个文章能有一点点帮助或收获,我就心满意足了。多思考,多问为什么。希望小伙伴们早点收到满意的offer! 越努力越幸运!

金九银十已经过了,就目前国内的面试模式来讲,在面试前积极的准备面试,复习整个 Java 知识体系将变得非常重要,可以很负责任的说一句,复习准备的是否充分,将直接影响你入职的成功率。但很多小伙伴却苦于没有合适的资料来回顾整个 Java 知识体系,或者有的小伙伴可能都不知道该从哪里开始复习。我偶然得到一份整理的资料,不论是从整个 Java 知识体系,还是从面试的角度来看,都是一份含技术量很高的资料。

三面蚂蚁核心金融部,Java开发岗(缓存+一致性哈希+分布式)

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
                     Thread.sleep(20);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+“:”+number);

number++;

}else {

break;

}

}

}

}

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-TSga3mzX-1713470216014)]

[外链图片转存中…(img-9Z1Wtiye-1713470216015)]

[外链图片转存中…(img-2cniiPTA-1713470216015)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

就写到这了,也算是给这段时间的面试做一个总结,查漏补缺,祝自己好运吧,也希望正在求职或者打算跳槽的 程序员看到这个文章能有一点点帮助或收获,我就心满意足了。多思考,多问为什么。希望小伙伴们早点收到满意的offer! 越努力越幸运!

金九银十已经过了,就目前国内的面试模式来讲,在面试前积极的准备面试,复习整个 Java 知识体系将变得非常重要,可以很负责任的说一句,复习准备的是否充分,将直接影响你入职的成功率。但很多小伙伴却苦于没有合适的资料来回顾整个 Java 知识体系,或者有的小伙伴可能都不知道该从哪里开始复习。我偶然得到一份整理的资料,不论是从整个 Java 知识体系,还是从面试的角度来看,都是一份含技术量很高的资料。

[外链图片转存中…(img-S2MCs5fK-1713470216016)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值