JAVA 多线程机制(二)

主要内容

1.理解线程的并发性

2.线程的同步

3.线程的常用方法

  上一章中由于线程的并发性导致了多线程的执行总是会出现一些问题。。线程的并发性是程序员不可控制

的,也是不可避免的,线程的并发性往往会导致问题的出现。。那么我们为什么要控制线程的并发性呢?

如说:一个公子管理负责人正在修改雇员的工资表,而一些雇员正在领取工资,如果允许这样做必然会造成

混乱,因此,工资管理负责人正在修改工资表的时候,不允许任何的雇员领取工资,也就是说雇员们必须执行

等待状态。。

public class tickets {
    public static void main(String[] args) {
         sel s=new sel();
         Thread t1=new Thread(s);
         Thread t2=new Thread(s);
         Thread t3=new     Thread(s);
         t1.start();
         t2.start();
         t3.start();
    }

}
class sel implements Runnable
{
    private int num=100;
    public void run()
    {
        while(true)
        {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if(num>0)
            {
                System.out.println(Thread.currentThread().getName()+"正在出售第"+num+"张票"+num--);
            }else
            {
                break;
            }
        }
    }
}

依然是卖票问题,上述的线程由于线程的并发性而导致了卖票窗口出现了问题。。

为了解决这一问题,我们引入线程的同步。。

2.线程的同步

 何为同步:我的理解就是:上述有三个线程,当t1线程启动的时候调用run()方法,那么同步函数也就起了作用,当t1执行run()

方法时,CPU分配给t1线程一把钥匙(并且只有一把),拿到这个钥匙之后开启synchronized函数的锁,然后进去执行里面的方法,

同时拿着钥匙,然后把门锁上,其他线程想访问这个函数的时候CPU没有钥匙,钥匙被线程t1拿进去了,所以其他的线程只能在线程池

中进行排队等待,当t1执行完毕后,把门打开,然后将钥匙还给CPU,然后t1线程或者消亡,或者进入阻塞状态,或者执行其他的过程

然后CPU再次把钥匙给在线程池中排队等待的线程,依次类推。。

(1)synchronized 同步函数

(2)synchronized 同步代码块

同步函数:

public class tickets {
    public static void main(String[] args) {
         sel s=new sel();
         Thread t1=new Thread(s);
         Thread t2=new Thread(s);
         Thread t3=new     Thread(s);
         t1.start();
         t2.start();
         t3.start();
    }

}
class sel implements Runnable
{
    private int num=100;
    public synchronized void run()//同步函数的建立
    {
        while(true)
        {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if(num>0)
            {
                System.out.println(Thread.currentThread().getName()+"正在出售第"+num+"张票"+num--);
            }else
            {
                break;
            }
        }
    }
}

那么上面卖票中出现的问题就得到了解决,就不会出现一张票被卖多次,或者是出现卖第0张票的可能了。。

同步代码块:

public class tickets {
    public static void main(String[] args) {
         sel s=new sel();
         Thread t1=new Thread(s);
         Thread t2=new Thread(s);
         Thread t3=new     Thread(s);
         t1.start();
         t2.start();
         t3.start();
    }

}
class sel implements Runnable
{
    private int num=100;
    public  void run()//同步代码块的建立
    {
        synchronized(this)
        {
        while(true)
        {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if(num>0)
            {
                System.out.println(Thread.currentThread().getName()+"正在出售第"+num+"张票"+num--);
            }else
            {
                break;
            }
        }
    }
    }
}

同步代码块的实现也可以避免线程的并发性,并且同步代码块比同步函数更具有优势,同步代码块的

效率也是比同步函数要高的。最重要的是同步代码块的好处在于:

      同步函数的锁只能是this,而同步代码块可以是任意一个obj对象,可以定义自己的类来定义自己的锁

同步代码块的速度也是比同步函数要更加快一些,应用的更加的广泛。。因此,在处理多线程安全问题的时候

最好使用同步代码块。。

  线程的常用方法

  1.start() 2.run() 3.sleep()4.isAlive()5.currentThread()6.interrupt()

前面的三个就不在进行介绍了。想必学习到了线程就知道这三个方法是什么意思了,isAlive()方法是判断

当前线程是否还活着。。currentThread()方法是获取当前执行线程的对象名,interrupt()方法是唤醒

休眠的线程。。下面举个例子。。。

/*
 * 比如说张小帅正在睡觉,那么正是上课时间
 * 张小帅睡觉线程正在执行,但是在上课时的
 * 老师这个线程看到了张小帅睡觉线程,然后
 * 直接叫醒了张小帅线程。。。
 * */
public class Demo_1_1 {
    public static void main(String[] args) {
        ClassRoom room=new ClassRoom();
        room.students.start();
        room.teacher.start();
    }
}
class ClassRoom implements Runnable
{
    Thread students,teacher;
    ClassRoom()
    {
        teacher=new Thread(this);
        students=new Thread(this);
        teacher.setName("张老师");
        students.setName("张小帅");
    }
    public void run()
    {
        if(Thread.currentThread()==students)
        {
            System.out.println(Thread.currentThread().getName()+"正在睡觉,不听课");
            try {
                Thread.sleep(1000*60*60);
            } catch (InterruptedException e) {
                System.out.println(students.getName()+"被唤醒");
            }
            System.out.println("开始听课");
        }
        else if(Thread.currentThread()==teacher)
        {
            for(int i=1;i<=3;i++)
            {
                System.out.println("上课");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            students.interrupt();
        }
    }
}

顺便提一嘴。。一个已经运行的线程在没有进入死亡状态时,不要再次分配实体,由于线程的分配只能引用

最后一个实体,那么先前的实体就会成为垃圾,并且垃圾回收站不会去进行回收,因为JVM会认为那个垃圾

实体正在运行,如果突然使其中断,那么必然会导致设备的损坏。。。

比如说:

Thread thread=new Thread(target);

thread.start();

如果再次执行下面的语句。。。

thread=new Thread(target);那么原本的实体就会成为垃圾。。。

就好比下面这样。。。。


因此在写多线程的时候一定要避免这样的问题发生。。。

        

 

时间: 2024-10-07 05:07:09

JAVA 多线程机制(二)的相关文章

Java多线程(二)、线程的生命周期和状态控制(转)

Java多线程(二).线程的生命周期和状态控制 分类: javaSE综合知识点 2012-09-10 16:11 15937人阅读 评论(3) 收藏 举报 一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态(runnable). 注意:不能对已经启动的线程再次调用start()方法,否则会出现java.lang.IllegalThreadSt

java多线程系列(二)

对象变量的并发访问 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理解能让知识更加简单易懂. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 java多线程系列(三)之等待通知机制 java多线程系列(四)之ReentrantLock的使用 线程安全 线程安全就是多线程访问时,采用了加锁机制,当一个

Java多线程感悟二

写在前面 这篇是Java多线程感悟的第二篇博客,主要讲述的JAVA层面对并发的一些支持.第一篇博客地址为:http://zhangfengzhe.blog.51cto.com/8855103/1607712  下一篇博客将介绍线程池和一些同步工具类. 目录 9.  并发内存模型及并发问题概述 10. volatile和synchronized原理分析 11. ThreadLocal原理及其在Struts/Spring中的应用 12. Atomic 13. Lock 并发内存模型及并发问题概述 首

Java多线程(二)

本文承接上一篇文章<Java多线程(一)>. 四.Java多线程的阻塞状态与线程控制 上文已经提到Java阻塞的几种具体类型.下面分别看下引起Java线程阻塞的主要方法. 1.join() join -- 让一个线程等待另一个线程完成才继续执行.如A线程线程执行体中调用B线程的join()方法,则A线程被阻塞,知道B线程执行完为止,A才能得以继续执行. 1 public class ThreadTest { 2 3 public static void main(String[] args)

Java总结篇系列:Java多线程(二)

四.Java多线程的阻塞状态与线程控制 上文已经提到Java阻塞的几种具体类型.下面分别看下引起Java线程阻塞的主要方法. 1.join() join -- 让一个线程等待另一个线程完成才继续执行.如A线程线程执行体中调用B线程的join()方法,则A线程被阻塞,知道B线程执行完为止,A才能得以继续执行. 1 public class ThreadTest { 2 3 public static void main(String[] args) { 4 5 MyRunnable myRunna

【搞懂Java多线程之二】多线程调度及守护进程

在前一篇文章中说到,所有处在就绪状态中的线程,操作系统会选择优先级最高的优先进行调度,那么是不是优先级高的线程就一定比优先级低的线程先执行呢?线程的优先级又是怎么划分的呢?这篇文章,楼楼就要来说说这个问题啦!欢迎关注我的个人博客主页www.anycodex.com 1.线程的优先级 在Java中,线程优先级的范围为0-10,整数值越大,说明优先级更高. 几个相关的宏定义: MAX_PRIORITY 10,最高优先级 MIN_PRIORITY 1,最低优先级 NORM_PRIORITY 5,默认优

Java多线程(二) —— 线程安全、线程同步、线程间通信(含面试题集)

一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会引起此共享资源的不一致性.因此,为避免线程安全问题,应该避免多线程环境下对此共享资源的并发访问. 线程安全问题多是由全局变量和静态变量引起的,当多个线程对共享数据只执行读操作,不执行写操作时,一般是线程安全的:当多个线程都执行写操作时,需要考虑线程同步来解决线程安全问题. 二.线程同步(synchr

java多线程解读二(内存篇)

线程的内存结构图 一.主内存与工作内存 1.Java内存模型的主要目标是定义程序中各个变量的访问规则.此处的变量与Java编程时所说的变量不一样,指包括了实例字段.静态字段和构成数组对象的元素,但是不包括局部变量与方法参数,因为它们是线程私有的,不会被共享. 2.Java内存模型中规定了所有的变量都存储在主内存中,每条线程还有自己的虚拟内存.线程的虚拟内存中保存了该线程使用到的变量到主内存副本拷贝.线程对变量的所有操作(读取.赋值)都必须在自己的虚拟内存中进行,而不能直接读写主内存中的变量.不同

java多线程(二)锁对象

转载请注明出处:http://blog.csdn.net/xingjiarong/article/details/47679007 在上一篇博客中,我们讨论了Race Condition现象以及它产生的原因,现在我们知道它是不好的一种现象了,那么我们有什么方法避免它呢.最直接有效的方式就是放弃多线程,直接改为使用单线程但操作数据,但是这是不优雅的,因为我们知道有时候,多线程有它自己的优势.在这里我们讨论两种其他的方法--锁对象和条件对象. 锁对象 java SE5.0之后为实现多线程的互斥引入了