安全

线程安全

如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

解决思想:当一个线程进入数据操作的时候,无论是否休眠,其他线程只能等待。

  • 通过线程休眠,出现安全问题
  • 解决安全问题,java程序,提供了一个技术叫做同步技术
  • 公式:
  • synchronized(任意对象){线程要操作的共享数据}
  • 同步代码块

任意对象的作用

任意对象:同步对象,同步锁,对象监视器obj

同步保证安全性:没有锁的线程不能执行只能等

线程遇到同步代码块后,线程判断同步锁还有没有

同步锁,有!

获取锁,进入同步,去执行,在执行完毕后,出去同步代码块后,线程在将锁对象换回去。

如果线程在同步线程中,进行了休眠,此时另外一个线程执行,遇到同步代码块,判断对象锁还有没有。没有锁的线程,不能进入同步中执行,被阻挡在同步代码块外面。

加了同步后,线程进同步判断锁,获取锁,出同步释放锁,导致程序运行速度的下降。

没有锁的线程不能进入同步。在同步中的线程不出去不会释放锁。

package cn.hiluna.demo;

/**
 * 通过线程休眠,出现安全问题
 * 解决安全问题,java程序,提供了一个技术叫做同步技术
 * 公式:
 *      synchronized(任意对象){线程要操作的共享数据}
 * 同步代码块
 * @author zhang
 */
public class Tickets implements Runnable{
    //定义可以出售的票源
    private int ticket = 100;
    private Object object = new Object();

    @Override
    public void run() {
        while (true){
            //线程共享数据,保证安全,加入同步代码块
            synchronized(object){
            //对票数进行判断,大于0,可以出售,变量--操作
                if (ticket > 0){
                    try {
                        Thread.sleep(10);
                    } catch (Exception e) {
                    }
                    System.out.println(Thread.currentThread().getName()+"出售第"+ticket-- +"票");
                }
            }
        }
    }
}
package cn.hiluna.demo;

/**
 * 多线程并发访问同一个数据资源
 * 3个线程同时并发,对一个票资源进行出售
 * @author zhang
 */
public class ThreadDemo {
    public static void main(String[] args) {
        //创建runnable接口实现类对象
        Tickets tickets = new Tickets();
        //创建3个Thread对象,传递runnable接口实现类
        Thread thread0 = new Thread(tickets);
        Thread thread1 = new Thread(tickets);
        Thread thread2 = new Thread(tickets);

        thread0.start();thread1.start();thread2.start();

    }
}

上面的方式代码比较繁琐,因此可以使用同步方法。

采用同步方法形式,解决线程的安全问题

好处:代码量简洁 将线程的共享数据,和同步,抽取到一个方法中 在方法的声明上,加入同步关键字

问题:同步方法的锁是?
同步方法中的对象锁是本类对象引用this

如果方法是静态的呢,同步锁有吗?有,绝对不是this,而是本类自己.class。
静态方法同步锁是:本类类名.class。

package cn.hiluna.demo01;

import cn.hiluna.demo.*;

/**
 * 采用同步方法形式,解决线程的安全问题 
 * 好处:代码量简洁 将线程的共享数据,和同步,抽取到一个方法中 在方法的声明上,加入同步关键字
 *
 * @author zhang
 */
public class Tickets implements Runnable {

    //定义可以出售的票源
    private int ticket = 100;
    @Override
    public void run() {
        while (true) {
            payTicket();
        }
    }
    public synchronized void payTicket() {
        //对票数进行判断,大于0,可以出售,变量--操作
        if (ticket > 0) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {
            }
            System.out.println(Thread.currentThread().getName() + "出售第" + ticket-- + "票");
        }
    }
}

使用JDK1.5的接口lock,替换同步代码块,实现线程安全 Lock接口的方法: lock()获取锁 unlock()释放锁

实现类ReentrantLock

package cn.hiluna.demo02;

import cn.hiluna.demo.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 使用JDK1.5的接口lock,替换同步代码块,实现线程安全 Lock接口的方法: lock()获取锁 unlock()释放锁
 * 实现类ReentrantLock
 *
 * @author zhang
 */
public class Tickets implements Runnable {

    //定义可以出售的票源
    private int ticket = 100;
    //在类的成员位置创建Lock接口的实现类对象
    private Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            //调用Lock接口方法lock获取锁
            lock.lock();
            //对票数进行判断,大于0,可以出售,变量--操作
            if (ticket > 0) {
                try {
                    Thread.sleep(10);
                    System.out.println(Thread.currentThread().getName() + "出售第" + ticket-- + "票");
                } catch (Exception e) {
                } finally {
                    //释放锁,调用Lock接口方法unlock
                    lock.unlock();
                }
            }
        }
    }
}


线程同步:死锁

同步锁使用的弊端:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。这是容易引发一种现象:程序出现无限等待,这种现象我们称为死锁。

package cn.hiluna.demo03;
public class LockA {
    private LockA(){}

    public final static LockA lockA = new LockA();
}


package cn.hiluna.demo03; public class LockB { private LockB(){} public static final LockB lockB = new LockB(); }
package cn.hiluna.demo03;

public class DeadLock implements Runnable{
    private  int i = 0 ;
    public void run(){
        while (true) {            
            if (i%2 == 0) {
                //先进入A同步,在进入B同步
                synchronized(LockA.lockA){
                    System.out.println("if...locka");
                    synchronized(LockB.lockB){
                        System.out.println("if...lockb");
                    }
                }
            }else{
                //先进入B同步,在进入A同步
                synchronized(LockB.lockB){
                    System.out.println("else...lockb");
                    synchronized(LockA.lockA){
                        System.out.println("else...locka");
                    }
                }
            }
            i++;
        }
    }
}

package cn.hiluna.demo03;
public class DeadLockDemo {
    public static void main(String[] args) {
        DeadLock deadLock = new DeadLock();
        Thread t0 = new Thread(deadLock);
        Thread t1 = new Thread(deadLock);

        t0.start();
        t1.start();
    }
}


线程等待与唤醒案例的实现线程等待与唤醒案例的实现

%title插图%num

资源类:


package cn.hiluna.demo04; /** * 定义资源类,2个成员变量 * name,sex * 同时又2个线程,对资源中的变量操作 * 一个对name,age赋值 * 一个对name,age做变量的输出打印 * @author zhang */ public class Resource { public String name; public String sex; public boolean flag = false; }

Input类:

package cn.hiluna.demo04;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 输入的线程,对资源对象Resource中成员变量赋值 一次张三,男 一次李四,女
 *
 * @author zhang
 */
public class Input implements Runnable {

    private Resource r;

    public Input(Resource r) {
        this.r = r;
    }

    @Override
    public void run() {
        int i = 0;
        while (true) {
            synchronized (r) {
                //标记是true,等待
                if (r.flag) {
                    try {
                        r.wait();
                    } catch (InterruptedException ex) {
                        Logger.getLogger(Input.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }

                if (i % 2 == 0) {
                    r.name = "张三";
                    r.sex = "男";
                } else {
                    r.name = "lisi";
                    r.sex = "nv";
                }
                //将对方线程换线,标记改为true
                r.flag = true;
                r.notify();
            }
            i++;
        }
    }
}

Output类:

package cn.hiluna.demo04;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 输出线程,对资源对象Resource中成员变量,输出变量值
 *
 * @author zhang
 */
public class Output implements Runnable {

    private Resource r;

    public Output(Resource r) {
        this.r = r;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (r) {
                //判断标记,如果是false,等待
                if (!r.flag) {
                    try {
                        r.wait();
                    } catch (InterruptedException ex) {
                        Logger.getLogger(Output.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                System.out.println(r.name + "..." + r.sex);
                //标记改为false
                r.flag = false;
                r.notify();
            }
        }
    }
}

主类:


package cn.hiluna.demo04; /** *开启输入和输出线程,实现程序的赋值和打印值 * @author zhang */ public class ThreadDemo { public static void main(String[] args) { Resource r = new Resource(); Input input = new Input(r); Output output = new Output(r); Thread tin = new Thread(input); Thread tou = new Thread(output); tin.start(); tou.start(); } }
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇