java wait 线程安全吗_Java学习线程安全

线程同步(线程安全处理Synchronized)

线程同步的两种方式:

1、同步代码块

2、同步方法

同步代码块

同步代码块: 在代码块声明上 加上synchronized

synchronized (锁对象) {

可能会产生线程安全问题的代码

}

同步代码块中的锁对象可以是任意的对象;但多个线程时,要使用同一个锁对象才能够保证线程安全。

package com.oracle.demo01;

/*格式:

* synchronized(任意对象){

* 线程要操作的共享数据

* }

* 任意对象:同步对象、同步锁、对象监视器

* 同步怎么能保证安全性?

* 没有锁的线程不能执行,只能等待

*

* 线程获得CPU资源以后想要执行同步代码块的内容,它先去看一下同步锁有没有

* 如果有,那么你的线程获得锁,然后进入同步代码块执行代码,虽然在同步代码块中,线程休眠了

* 在此线程休眠时,其他线程获得资源想要执行同步代码块,它先去看一看有没有锁,一看,没有锁

* 它就被阻挡在代码块之后,只有等

* 休眠的线程睡完了,起来继续执行代码块中的内容,全部执行完代码块中的内容,就释放锁

* 然后其他线程获得锁,就可以继续执行了

*

* 线程安全了,那么执行速度就会变慢了

* */

public class Ticket implements Runnable {

private int ticket = 100;

Object obj = new Object();

@Override

public void run() {

// TODO Auto-generated method stub

while (true) {

synchronized (obj) {

if (ticket > 0) {

try {

Thread.sleep(10);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName() + "出售第" + (ticket--) + "张票");

}

}

}

}

}

package com.oracle.demo01;

public class Test {

public static void main(String[] args) {

Ticket t = new Ticket();

Thread t0 = new Thread(t);

Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

t0.start();

t1.start();

t2.start();

}

}

同步方法

同步方法:在方法声明上加上synchronized

public synchronized void method(){

可能会产生线程安全问题的代码

}

同步方法中的锁对象是 this

静态同步方法: 在方法声明上加上static synchronized

public static synchronized void method(){

可能会产生线程安全问题的代码

}

package com.oracle.demo02;

/*

*同步方法中有锁么?

*有锁,同步方法中的对象锁,就是本类对象引用 this

*StringBuffer:之所以安全,就是因为里面有同步方法,只要有同步,就安全,就慢

*StringBuilder:不安全,就是因为没有同步,就快

*

*如果你的同步方法时静态的,还有锁么?还是this么?

*有锁,不是this,是本类自己,也就是ticket.class 本类类名.class

* */

public class Ticket implements Runnable {

private int ticket = 100;

Object obj = new Object();

@Override

public void run() {

// TODO Auto-generated method stub

while (true) {

//synchronized (this)

synchronized (obj) {

method();

}

}

}

//同步代码块,代码更简洁

public synchronized void method() {

if (ticket > 0) {

try {

Thread.sleep(10);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName() + "出售第" + (ticket--) + "张票");

}

}

}

package com.oracle.demo01;

public class Test {

public static void main(String[] args) {

Ticket t = new Ticket();

Thread t0 = new Thread(t);

Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

t0.start();

t1.start();

t2.start();

}

}

Lock接口

Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。

常用方法:

f3c4f4ed4998d6fb670026cf72c80a18.png

package com.oracle.demo03;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

/*

* JDK5以后出现Lock接口的可以代替同步关键字

* 功能是一样的,但是更灵活

* */

public class Ticket implements Runnable {

private int ticket = 100;

//接口不能实例化对象,就用子类的引用

private Lock l=new ReentrantLock();

@Override

public void run() {

// TODO Auto-generated method stub

while (true) {

l.lock();

if (ticket > 0) {

try {

Thread.sleep(10);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName() + "出售第" + (ticket--) + "张票");

}else{

return;

}

l.unlock();

}

}

}

package com.oracle.demo03;

public class Test {

public static void main(String[] args) {

Ticket t = new Ticket();

Thread t0 = new Thread(t);

Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

t0.start();

t1.start();

t2.start();

}

}

死锁

死锁的前提就是:一个线程必须同时拥有两个对象的资源才能执行程序。

1.线程1 首先占有对象1,接着试图占有对象2

2. 线程2 首先占有对象2,接着试图占有对象1

3. 线程1 等待线程2释放对象2

4. 与此同时,线程2等待线程1释放对象1

就会。。。一直等待下去,直到天荒地老,海枯石烂,山无棱 ,天地合。。。

19719e0997de0c4196adfe22776c9e75.png

8949478.html

package com.oracle.demo04;

public class LockA {

private LockA() {

}

//保证A锁的唯一性

public final static LockA la = new LockA();

}

package com.oracle.demo04;

public class LockB {

private LockB() {

}

//保证了B锁的唯一性

public final static LockB lb = new LockB();

}

package com.oracle.demo04;

public class DeadLock implements Runnable {

private int i = 0;

@Override

public void run() {

while (true) {

if (i % 2 == 0) {

synchronized (LockA.la) {

System.out.println("if...LockA");

synchronized (LockB.lb) {

System.out.println("if...LockB");

}

}

} else {

synchronized (LockB.lb) {

System.out.println("else...LockB");

synchronized (LockA.la) {

System.out.println("else...LockA");

}

}

}

i++;

}

}

}

package com.oracle.demo04;

public class Test {

public static void main(String[] args) {

DeadLock dl = new DeadLock();

Thread t0 = new Thread(dl);

Thread t1 = new Thread(dl);

t0.start();

t1.start();

}

}

等待唤醒机制

线程之间的通信:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。

等待唤醒机制:通过一定的手段使各个线程能够有效的利用资源,该手段就是等待唤醒机制

等待唤醒机制所涉及到的方法:

wait():等待,将正在执行的线程释放其执行资格和执行权,并存储到线程池中

notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的

notifyAll():唤醒全部,可以将线程池中的所有wait()线程都唤醒

所谓唤醒:就是让线程池中的线程具备执行资格。必须注意:这些方法都是在同步中才有效。同时这些方法在使用时必须表明所属锁,这样才可以明确这些方法操作的是哪个锁上的线程。

这些方法都被定义在Object类中了,因为这些方法在使用时,必须表明所属锁,而锁又可以是任意的,能被任意对象调用的方法一定定义在Object类中。

5b1f16c6299373f1f568636abb12b922.png

例如:

9cbeb7450691debe513cfc9563bcedbb.png

输入线程向Resource中输入name ,sex ,输出线程从资源中输出,先要完成的任务是:

l 1.当input发现Resource中没有数据时,开始输入,输入完成后,叫output来输出。如果发现有数据,就wait();

l 2.当output发现Resource中没有数据时,就wait() ;当发现有数据时,就输出,然后,叫醒input来输入数据。

package com.oracle.demo05;

public class Resouse {

public String name;

public String sex;

public boolean flag=false;

}

//flag标记:为true的时候,赋值完成

// 为false的时候,获取值完成

//输入类:true,等待,false,赋值,赋值完成后,把flag变为true notify输出,自己wait()

//输出类:false,等待,true,取值,取值完成后,把flag变为false notify输入,自己wait()

package com.oracle.demo05;

public class Input implements Runnable {

private Resouse r;

public Input(Resouse r) {

this.r = r;

}

@Override

public void run() {

// 往资源对象中输入数据

int i = 0;

while (true) {

//r表明锁的唯一性

synchronized (r) {

if (r.flag) {

try {

r.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

if (i % 2 == 0) {

r.name = "张三";

r.sex = "女";

} else {

r.name = "lisi";

r.sex = "nan";

}

r.flag = true;

r.notify();

}

i++;

}

}

}

package com.oracle.demo05;

public class Output implements Runnable {

private Resouse r;

public Output(Resouse r) {

this.r = r;

}

@Override

public void run() {

// 从资源对象中输出数据

while (true) {

synchronized (r) {

if (!r.flag) {

try {

r.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

System.out.println(r.name + "..." + r.sex);

r.flag = false;

r.notify();

}

}

}

}

package com.oracle.demo05;

public class Test {

public static void main(String[] args) {

Resouse r = new Resouse();

Input in = new Input(r);

Output out = new Output(r);

Thread tin = new Thread(in);

Thread tout = new Thread(out);

tin.start();

tout.start();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值