黑马程序员【Java中的多线程】

Java中的多线程

首先,在开篇讲线程之前要说一个问题,我们知道多线程的执行原理是cpu在不同的线程中做着切换操作,而一提到多线程,大家首先想到的肯定是提高系统的运行效率,可是真的是这样的么?我们来借助一位大神博客中的代码就可以看出来有时单线程的运行效率要高于多线程:

import threading
from time import ctime

class MyThread(threading.Thread):
    def __init__(self, func, args, name):
        threading.Thread.__init__(self)
        self.name = name
        self.func = func
        self.args = args

    def run(self):
        print ‘starting‘, self.name, ‘at:‘,ctime()
        apply(self.func, self.args)
        print self.name, ‘finished at:‘, ctime()

def fun1(x):
    y = 0
    for i in range(x):
        y+=1

def fun2(x):
    y = 0
    for i in range(x):
        y+=1

def main():
    print ‘staring single thread at:‘,ctime()
    fun1(10000000)
    fun2(10000000)
    print ‘finished single thread at:‘,ctime()

    t1 = MyThread(fun1,(10000000,),fun1.__name__)
    t2 = MyThread(fun2,(10000000,),fun2.__name__)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    print ‘all done‘

if __name__ == ‘__main__‘:
    main()

程序的运行结果就是单线程比多线程的运行效率有着明显的提升,可这是为什么呢?还是因为线程的执行原理,是因为cpu在你的各个线程之间做着快速的切换操作,那么如果你是单核的cpu那么你的程序就没有必要验证多线程了,因为在各个线程之间的切换都是在一个cpu下执行的,只有在双核或多核的cpu才可以以不同的cpu来执行不同的线程来提高程序的运行效率。相信很多人在自己的电脑上实验过多线程的执行时间问题,对于得出的结果疑惑不已,其实就是因为你的cpu的原因了。

好了,提了一个小的问题,现在我们切入主题,说一下java中的线程。线程有两种两种创建方式,一种是直接继承Thread类并且覆盖其run()方法,但是我们知道java只支持单继承,那么如果我们的类还有一个父类,那么就难以实现这个方法。第二种是通过声明实现Runnable接口,然后实现run方法,然后可以分配该类的实例,在创建Thread类的时候,通过带参构造来传递并启动,Runnable为非Thread类提供了一种激活方式。那么下面我们就用代码演示一下第二种创建线程的方式:

class Show implements Runnable {
    private int num = 100;
    @Override
    public void run() {
        while (true) {
                if (num > 0) {
                    System.out.println(Thread.currentThread().getName()+":"+num);
                    num--;
                } else {
                    break;
                }
        }
    }
}
public class MyMain {
    public static void main(String[] args) {
        Show show = new Show();
        Thread t = new Thread(show);
        Thread t1 = new Thread(show);
        Thread t2 = new Thread(show);
        Thread t3 = new Thread(show);
        t.start();
        t1.start();
        t2.start();
        t3.start();
    }
}

这样就完成了四个线程在同时执行循环,直到num见到0为止,可是如果我们开他的运行结果,会发现一个很明显的问题:

这是我截图了一部分运行结果,可以明显的发现出现了四次100,那么这是为什么呢?就拿这段代码打个比方,当你的t线程拿到cpu的执行权时,执行内部的run方法,进入循环判定if条件,判定num>0通过,进入内部代码块打印出num的值,可是就在这个时候,另外一个线程t1获得了执行权,同样进入循环判定if条件当判定num>0通过时,num的值并未改变,可是却依旧打印出num的值,这样就出现了两个相同的值,同样的当有多个这样的状况出现时,就会出现多个重复的值,这就是线程的安全问题,也就是当多个线程同时操作同一个variable,就可能会出现不可预知的结果。那么该怎样解决这样的问题呢?这就用到了synchronized(同步函数),为线程加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。可能光靠说的很难理解,下面还是展示一段上面代码的修改版,然后我们再来看看运行结果:

class Show implements Runnable {
    private int num = 100;
    Object obj = new Object();
    @Override
    public void run() {
        while (true) {
            synchronized (obj) {
                if (num > 0) {
                    System.out.println(Thread.currentThread().getName()+":"+num);
                    num--;
                } else {
                    break;
                }
            }
        }
    }
}
public class MyMain {
    public static void main(String[] args) {
        Show show = new Show();
        Thread t = new Thread(show);
        Thread t1 = new Thread(show);
        Thread t2 = new Thread(show);
        Thread t3 = new Thread(show);
        t.start();
        t1.start();
        t2.start();
        t3.start();
    }
}

这次再看代码的运行结果时,我们会发现刚刚的重复问题不见了,而且程序虽然还是在各个线程之间切换,可是打印出来num的顺序却是固定的有序的了,就像单线程的循环一样100到1,这就是线程的安全问题,其实解决的问题很简单,就是在需要判定并且改变值的代码外部加上synchronized块,他会在你的线程进入该块的时候做一个判定,如果有正在使用该方法的线程,如果有的话,会拦截该线程,直到正在使用synchronized方法的线程失去执行权的时候,才会再运行该线程。没有使用的线程,执行线程并锁定线程。在使用synchronized时需要注意死锁问题。

时间: 2024-12-27 20:28:56

黑马程序员【Java中的多线程】的相关文章

黑马程序员------Java中多线程学习总结(一)

Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! 一.多线程的概念 进程:是一种“自包容”的运行程序,有自己的地址空间. 基于进程的特点是允许计算机同时运行两个或更多的程序 线程:是进程内部单一的一个顺序控制流 . 基于线程的多任务处理环境中,线程是最小的处理单位. 在Java中,一个应用程序可以包含多个线程.每个线程执行特定的任务,并可与其他线程并发执行.多线程使系统的空转时间减少,提高了CPU的利用率.多线程编程隐藏了CPU在任务之间切换的事实. 二.创建

黑马程序员-Java基础之多线程

多线程 进程:正在进行中的程序.其实进程就是一个应用程序运行时的内存分配空间. 线程:其实就是进程中一个程序执行控制单元,一条执行路径.进程负责的是应用程序的空间的标示.线程负责的是应用程序的执行顺序. 一个进程至少有一个线程在运行,当一个进程中出现多个线程时,就称这个应用程序是多线程应用程序,每个线程在栈区中都有自己的执行空间,自己的方法区.自己的变量. jvm在启动的时,首先有一个主线程,负责程序的执行,调用的是main函数.主线程执行的代码都在main方法中. 当产生垃圾时,收垃圾的动作,

黑马程序员-java中的反射总结

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- Java 反射总结 类装载器工作机制 类装载器就是寻找类的节码文件并构造出类在JVM 内部表示对象的组件.在Java 中, 类装载器把一个类装入JVM 中,要经过以下步骤: 1.装载:查找和导入Class 文件: 通过一个类的全限定名来获

黑马程序员------Java中jdk1.5新特性

Java培训.Android培训.iOS培训..Net培训.期待与您交流! JDK1.5新特性: 为什么会出现新特性: 新的技术出现是为了解决老的问题,Java语言为了提高开发者的开发效率,对之前的某些不利于提高效率的技术进行改进. 静态导入: 静态导入:可以导入某个类下的静态方法,静态导入后,可以不写类名而直接使用此类下的静态方法. 语法:import static 包名.类名.静态方法 代码示例: package com.itheima.day1; /** * 静态导入 * @author

黑马程序员————java中的网络编程

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- java中的网络编程 一.网络编程概述:基于互联网的编程 就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换. 二.网络模型:OSI和TCP/IP 1.OSI(Open System Interconnection开放系统互连

黑马程序员------Java中GUI(图形用户界面)学习总结

Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! GUI: Graphical User Interface(图形用户接口). 即用图形的方式,来显示计算机操作的界面,以方便用户更容易更直观地操作. Java中为GUI提供的对象都在Java.Awt和Javax.Swing两个包中. java.Awt: Abstract Window ToolKit (抽象窗口工具包). 需要调用本地系统方法实现功能,属于重量级控件. javax.Swing: 在AWT的基础上

黑马程序员-Java中的基本数据类型

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- Java中的数据类型分为两个大类:基本数据类型和引用数据类型. 其中基本数据类型又可以分为四类:整型数据类型,小数数据类型,字符类型,布尔型. 整型数据类型还分为:byte,short,int(整型),long(长整型).默认为int型.

黑马程序员————java中的抽象类

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 抽象类集中的体现了java面向对象的特性,对于每一种事物通过五个方面:属性,方法,构造器,代码块,内部类,来重新解构再进行组装,然后将类似的事物归为一类,这是面向对象的思想.java中常说万物皆对象,那么很显然我们可以进一步的将其中的方法

黑马程序员------Java中多线程学习总结(二)

Java培训.Android培训.iOS培训..Net培训,期待您的交流 在Java多线程中,如果有多个线程同时操作共享数据时,就可能会发生数据异常 如下面这段代码: /* * 模拟卖票 */ class Ticket implements Runnable { private int tick = 10; Object obj = new Object(); public void run() { while(true) { if(tick>0) { try{Thread.sleep(10);

黑马程序员--Java中的反射逻辑

------- <a href="http://www.itheima.com" target="blank">android培训</a>.<a href="http://www.itheima.com" target="blank">java培训</a>.期待与您交流! ---------- 1 .      反射是在运行状态中,对于任意一个类(class文件),都能够知道这个