zoukankan      html  css  js  c++  java
  • 多线程2

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


    其实,线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

    演示卖票多线程案例:
    package cn.itcast.selltickets;

    public class TheadDemo {

    public static void main(String[] args) {
    Ticket ticket = new Ticket();
    Thread t0 = new Thread(ticket);
    Thread t1 = new Thread(ticket);
    Thread t2 = new Thread(ticket);
    t0.start();
    t1.start();
    t2.start();
    }
    }

    package cn.itcast.selltickets;

    public class Ticket implements Runnable {


    private int num = 100;

    public void run() {
    while(true) {
    if (num > 0) {
    try {
    Thread.sleep(100);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName() + "出售第" + num--);
    }
    }
    }
    }


    Thread-0出售第100
    Thread-1出售第99
    Thread-2出售第100
    Thread-0出售第98
    Thread-1出售第97
    Thread-2出售第96
    Thread-0出售第95
    Thread-1出售第94
    Thread-2出售第93
    Thread-0出售第92
    Thread-2出售第91
    Thread-1出售第90
    Thread-0出售第88
    Thread-2出售第89
    Thread-1出售第87
    Thread-0出售第86
    Thread-1出售第85
    Thread-2出售第84
    Thread-0出售第83
    Thread-1出售第82
    Thread-2出售第81
    Thread-0出售第80
    Thread-2出售第79
    Thread-1出售第78
    Thread-0出售第77
    Thread-1出售第76
    Thread-2出售第75
    Thread-0出售第74
    Thread-2出售第73
    Thread-1出售第72
    Thread-0出售第71
    Thread-2出售第70
    Thread-1出售第69
    Thread-0出售第68
    Thread-1出售第67
    Thread-2出售第66
    Thread-0出售第65
    Thread-1出售第64
    Thread-2出售第63
    Thread-0出售第62
    Thread-2出售第61
    Thread-1出售第60
    Thread-0出售第59
    Thread-2出售第58
    Thread-1出售第57
    Thread-0出售第56
    Thread-1出售第55
    Thread-2出售第54
    Thread-0出售第53
    Thread-2出售第52
    Thread-1出售第51
    Thread-0出售第50
    Thread-1出售第49
    Thread-2出售第49
    Thread-0出售第48
    Thread-1出售第47
    Thread-2出售第46
    Thread-0出售第45
    Thread-2出售第44
    Thread-1出售第43
    Thread-0出售第42
    Thread-1出售第41
    Thread-2出售第40
    Thread-0出售第39
    Thread-2出售第38
    Thread-1出售第37
    Thread-0出售第36
    Thread-1出售第35
    Thread-2出售第34
    Thread-0出售第33
    Thread-2出售第32
    Thread-1出售第31
    Thread-0出售第30
    Thread-2出售第29
    Thread-1出售第28
    Thread-0出售第27
    Thread-2出售第26
    Thread-1出售第25
    Thread-0出售第24
    Thread-1出售第23
    Thread-2出售第22
    Thread-0出售第21
    Thread-2出售第20
    Thread-1出售第19
    Thread-0出售第18
    Thread-2出售第17
    Thread-1出售第16
    Thread-0出售第15
    Thread-2出售第14
    Thread-1出售第13
    Thread-0出售第12
    Thread-1出售第11
    Thread-2出售第10
    Thread-0出售第9
    Thread-2出售第8
    Thread-1出售第7
    Thread-0出售第6
    Thread-1出售第5
    Thread-2出售第4
    Thread-0出售第3
    Thread-1出售第2
    Thread-2出售第1
    Thread-0出售第0
    Thread-1出售第-1

    用同步代码块synchronized解决
    package cn.itcast.selltickets;

    public class Ticket implements Runnable {

    private int num = 100;

    private Object o = new Object();

    public void run() {
    while (true) {
    synchronized (o) {
    if (num > 0) {
    try {
    Thread.sleep(100);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName() + "出售第" + num--);
    }
    }
    }
    }
    }

    用同步方法解决
    package cn.itcast.selltickets;

    public class Ticket implements Runnable {

    private int num = 100;


    public synchronized void run() {
    while (true) {
    if (num > 0) {
    try {
    Thread.sleep(100);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName() + "出售第" + num--);
    }
    }
    }
    }

    java中提供了线程同步机制,它能够解决上述的线程安全问题。
    线程同步的方式有两种:
    ? 方式1:同步代码块
    ? 方式2:同步方法
    同步代码块中的锁对象可以是任意的对象;但多个线程时,要使用同一个锁对象才能够保证线程安全。

    1.2.2 同步方法
    ? 同步方法:在方法声明上加上synchronized
    public synchronized void method(){
    可能会产生线程安全问题的代码
    }
    同步方法中的锁对象是 this

    ? 静态同步方法: 在方法声明上加上static synchronized
    public static synchronized void method(){
    可能会产生线程安全问题的代码
    }
    静态同步方法中的锁对象是 类名.class


    用lock接口解决安全性
    package cn.itcast.selltickets;

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;

    public class Ticket implements Runnable {

    private int num = 100;


    private Lock lock = new ReentrantLock();
    public void run() {
    while (true) {
    lock.lock();
    if (num > 0) {
    try {
    Thread.sleep(100);
    System.out.println(Thread.currentThread().getName() + "出售第" + num--);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }finally {
    lock.unlock();

    }
    }

    }
    }
    }


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


    死锁代码实现
    package cn.itcast.deadlock;

    public class DeadLock implements Runnable {

    private int i = 0;
    @Override
    public void run() {
    // TODO Auto-generated method stub
    while(true) {
    if (i % 2 == 0) {
    synchronized(LockA.locka){
    System.out.println("if...locka" + Thread.currentThread().getName());
    synchronized(LockB.lockb) {
    System.out.println("if...lockb" + Thread.currentThread().getName());
    }
    }
    }else {
    synchronized (LockB.lockb) {
    System.out.println("else...lockb" + Thread.currentThread().getName());
    synchronized (LockA.locka) {
    System.out.println("else...locka" + Thread.currentThread().getName());
    }
    }
    }
    //i=8,刚从if出来,正准备加1,这时cpu被另一个线程抢了,另一个想成走if,把A锁拿了,这时,cpu又被抢了另一个线程i++,走else,把B锁抢了
    //,这时拿到A锁的线程即使抢到cpu资源由于没有b锁,也阻塞了,另一个线程同样的.
    i++;
    }
    }

    }


    package cn.itcast.deadlock;

    public class Demo {

    public static void main(String[] args) {
    DeadLock dead = new DeadLock();
    Thread t0 = new Thread(dead);
    Thread t1 = new Thread(dead);
    t0.start();
    t1.start();
    }
    }


    package cn.itcast.deadlock;

    public class LockA {
    private LockA() {
    }

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


    package cn.itcast.deadlock;

    public class LockB {

    private LockB(){}
    public static final LockB lockb = new LockB();
    }


    if...lockaThread-0
    if...lockbThread-0
    else...lockbThread-0
    else...lockaThread-0
    if...lockaThread-0
    if...lockbThread-0
    else...lockbThread-0
    else...lockaThread-0
    if...lockaThread-0
    if...lockbThread-0
    else...lockbThread-0
    if...lockaThread-1

    线程通信:
    package cn.itcast.threadnotify;

    public class Demo {

    public static void main(String[] args) {
    Resource r = new Resource();
    Output out = new Output(r);
    Input in = new Input(r);
    Thread t0 = new Thread(in);
    Thread t1 = new Thread(out);
    t0.start();
    t1.start();


    }
    }

    package cn.itcast.threadnotify;

    public class Input implements Runnable {

    private Resource r;

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

    @Override
    public void run() {
    // TODO Auto-generated method stub
    int i = 0;
    while (true) {
    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 = "nv";
    }
    //将对方线程唤醒,标记改为true
    r.flag = true;
    r.notify();
    }
    i++;
    }
    }

    }

    package cn.itcast.threadnotify;

    public class Output implements Runnable {

    private Resource r;

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

    @Override
    public void run() {
    // TODO Auto-generated method stub

    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 cn.itcast.threadnotify;

    public class Resource {

    public String name;
    public String sex;
    public boolean flag = true;

    }

    在开始讲解等待唤醒机制之前,有必要搞清一个概念——线程之间的通信:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制。

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

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

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

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

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

    仔细查看JavaAPI之后,发现这些方法 并不定义在 Thread中,也没定义在Runnable接口中,却被定义在了Object类中,为什么这些操作线程的方法定义在Object类中?

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

    l  同步锁

    多个线程想保证线程安全,必须要使用同一个锁对象

    n  同步代码块

             synchronized (锁对象){

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

    }

                               同步代码块的锁对象可以是任意的对象

     

    n  同步方法

             public synchronized void method()

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

    }

                               同步方法中的锁对象是 this

    n  静态同步方法

    public synchronized void method()

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

    }

    静态同步方法中的锁对象是 类名.class

     

    l  多线程有几种实现方案,分别是哪几种?

             a, 继承Thread类

             b, 实现Runnable接口

             c, 通过线程池,实现Callable接口

    l  同步有几种方式,分别是什么?

             a,同步代码块

             b,同步方法

               静态同步方法

    l  启动一个线程是run()还是start()?它们的区别?

             启动一个线程是start()

             区别:

                      start: 启动线程,并调用线程中的run()方法

                      run  : 执行该线程对象要执行的任务

    l  sleep()和wait()方法的区别

             sleep: 不释放锁对象, 释放CPU使用权

                               在休眠的时间内,不能唤醒

                      wait(): 释放锁对象, 释放CPU使用权

                               在等待的时间内,能唤醒

    l  为什么wait(),notify(),notifyAll()等方法都定义在Object类中

             锁对象可以是任意类型的对象

  • 相关阅读:
    我的WCF之旅(1):创建一个简单的WCF程序
    网页设计中颜色的搭配
    CSS HACK:全面兼容IE6/IE7/IE8/FF的CSS HACK
    UVa 1326 Jurassic Remains
    UVa 10340 All in All
    UVa 673 Parentheses Balance
    UVa 442 Matrix Chain Multiplication
    UVa 10970 Big Chocolate
    UVa 679 Dropping Balls
    UVa 133 The Dole Queue
  • 原文地址:https://www.cnblogs.com/zjj1996/p/9108045.html
Copyright © 2011-2022 走看看