JAVA基础--Thread多线程简单应用(2)

上次学习了线程的创建,已级简单应用,这次来看看线程安全,及同步锁 synchronized 的作用:

package thread;

/**
 * Synchronized 同步锁, 线程安全;
 * 
 * 买票举例测试
 **/
public class MyTheard3 {
    /**
     * 知识点: 
     * 1, 什么是线程安全? 
     *  线程安全: 就是当   多个线程 同时共享同一个 全局变量 的时候,做 写 的操作时,数据的不可控性;
     *  
     * 2, 什么是线程同步?
     *  线程同步,是为了保证数据的原子性;保证数据的安全;
     *  
     * 3, 同步锁: 
     * synchronized(Object) {
     *      包含需要同步的代码,这个地方一次只能有一个线程执行;
     * }
     * 
     * 4, 同步的前提:
     *  (1), 必须要有两个或两个以上的线程;
     *  (2), 必须是多个线程使用同一把锁;
     *  
     * 5, 同步锁的作用: 
     *   保证同步中只能有一个线程运行;
     *   
     * 6, 原理: 
     *  (1), 当多个线程同时执行时,如果有一个线程抢到了锁,那么该线程执行,其他线程就算有CPU执行权也要等待,等抢到锁的线程释放了锁后,其他线程在继续抢锁;
     *      (锁就相当于一个身份令牌,有锁才能执行,而锁只有一把)(举例: 抢厕所)
     *  
     *  (2), 只有当代码执行完毕,或者抛出异常时,才会释放锁;
     *  
     *  
     * 7, 优点: 解决了线程安全问题;
     * 
     * 8, 缺点: 需要抢锁,消耗CPU资源,会发生死锁问题; 
     * 
     * */
    
    
    
    public static void main(String[] args) {
        // 两个线程必须使用同一个run()
        Send1 send = new Send1();
        Thread send1 = new Thread(send,"窗口1:");
        Thread send2 = new Thread(send,"窗口2:");
        
        send1.start();
        send2.start();
        
    }
    
    
    
    
    
    
}

/**
 * 售票线程
 * */
class Send1 implements Runnable{
    /*总票数,线程的全局变量*/
    private static int total = 100;
    
    /*线程中的锁*/
    Object object = new Object();
    
    @Override
    public void run() {
        while(total>0){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            stale();
        }
    }
    
    private void stale(){
        //同步锁:
        synchronized (object) {
            //每次只能有一个线程执行
            if(total>0){
                System.out.println(Thread.currentThread().getName()+"卖出第"+((100-total)+1)+"张票");
                total--;
            }
        }
    }
    
}


2, 使用this锁:

private void stale(){
        //同步锁 this :
        synchronized (this) {
            //每次只能有一个线程执行
            if(total>0){
                System.out.println(Thread.currentThread().getName()+"卖出第"+((100-total)+1)+"张票");
                total--;
            }
        }
    }

 

3, 使用同步函数:


    //同步函数: (synchronized修饰的方法)
    private synchronized void stale(){
        //每次只能有一个线程执行
        if(total>0){
            System.out.println(Thread.currentThread().getName()+"卖出第"+((100-total)+1)+"张票");
            total--;
        }
    }

4: 同步函数使用的就是this锁;

5: 总结: 同步函数和同步代码块可以实现同步,只要同步代码块使用this锁即可;

6: 静态同步函数:

//静态同步函数:(static synchronized修饰的方法, 使用  Send1.class 锁)
    private static synchronized void stale2(){
      //每次只能有一个线程执行
        if(total>0){
            System.out.println(Thread.currentThread().getName()+"卖出第"+((100-total)+1)+"张票");
            total--;
        }
    }

静态同步函数使用 当前类的字节码 锁;

7: 总结 : 同步函数和静态同步函数不能实现同步;

 

8: 多线程的可见性: volatile;

package thread;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 多线程的可见性
 * 
 * */
public class MyTheard4 {
    /**
     * 知识点: 
     * 
     * 1, 多线程的三大特性 : 原子性; 可见性; 有序性; 
     * 
     * 2, 什么是JAVA内存模型?
     *    JAVA内存模型分为: 主内存(主要存放共享的全局变量), 私有内存(该线程的私有变量); (属于 多线程可见性JMM方面)
     *    JAVA内存模型,决定一个线程与另一个线程是否可见; (线程安全问题)
     *    
     * 3, volatile 可见性;
     * 
     * 4, AtomicInteger (JDK1.5并发包中的);
     * */
    
    
    public static void main(String[] args) {
        TheardTest thread = new TheardTest();
        Thread t1 = new Thread(thread,"T1");
        Thread t2 = new Thread(thread,"T2");
        Thread t3 = new Thread(thread,"T3");
        Thread t4 = new Thread(thread,"T4");
        Thread t5 = new Thread(thread,"T5");
        
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        
        /**
         * 运行结果: 
         *  T2::1923
         *  T3::2876
         *  T5::3876
         *  T1::1922
         *  T4::4876
         * 结论 : volatile 不能保证原子性;
         * */
        
    }
    
    
    
}

class TheardTest implements Runnable{
    // 线程可见
    private volatile static int count = 0;
    
    @Override
    public void run() {
        for(int i=0;i<1000;i++){
            count++;
        }
        System.out.println(Thread.currentThread().getName()+"count::"+count);
    }
    
}

9: 多线程可见性: AtomicInteger

package thread;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 多线程的可见性
 * 
 * */
public class MyTheard4 {
    public static void main(String[] args) {
        TheardTest thread = new TheardTest();
        Thread t1 = new Thread(thread,"T1");
        Thread t2 = new Thread(thread,"T2");
        Thread t3 = new Thread(thread,"T3");
        Thread t4 = new Thread(thread,"T4");
        Thread t5 = new Thread(thread,"T5");
        
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        
    }
  
}

class TheardTest implements Runnable{
    // 线程可见
    private static AtomicInteger count2 = new AtomicInteger(0);
    
    @Override
    public void run() {
        for(int i=0;i<1000;i++){
            //等同于count++
            count2.incrementAndGet();
        }
        System.out.println(Thread.currentThread().getName()+"count2::"+count2);
    }
    
}

测试后,会发现: AtomicInteger可以保证数据原子性;

10, ThreadLocal 为每个线程创建局部变量,私有数据

class TheardTest implements Runnable{
    // 线程可见
    private volatile static int count = 0;
    // 共享数据,保证数据原子性
    private static AtomicInteger count2 = new AtomicInteger(0);
    // ThreadLocal: 为每个线程创建局部变量,私有数据
    private static ThreadLocal<Integer> count3 = new ThreadLocal<Integer>(){
        protected Integer initialValue() {
            return 0;
        };
    };
    
    @Override
    public void run() {
        for(int i=0;i<1000;i++){
            count++;
            count2.incrementAndGet();
            count3.set(count3.get()+1);
        }
        System.out.println(Thread.currentThread().getName()+"count::"+count);
        System.out.println(Thread.currentThread().getName()+"count2::"+count2);
        System.out.println(Thread.currentThread().getName()+"count3::"+count3.get());
    }
    
}

从打印结果可以发现,使用ThreadLocal创建的共享变量并没有共享;

转载于:https://my.oschina.net/u/3681868/blog/1603365

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值