多线程

原创 2015年07月07日 17:14:58

一、线程概述

线程和进程

线程是指进程内的一个执行单元,也是进程内的可调度实体.
进程:正在运行的程序。
线程:线程依赖于进程,CPU运行进程,其实就是在运行这个进程的线程。
区别:

  1. 地址空间:进程内的一个执行单元,进程至少有一个线程;它们共享进程的地址空间,而进程有自己独立的地址空间。
  2. 资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
  3. 线程是处理器调度的基本单位,但进程不是。

简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源。
Java语言无法直接操作系统,比如IO和我们的线程都要依赖于第三方语言,java语言又把这些内容封装成类,多线程封装成一个类Thread。Java语言如果要实现多线程,必须依赖于Thread这个类。

线程工作机理

线程的随机原理:多个程序其实是CPU的在做着高效切换执行的

二、创建线程

方法一:继承Thread类,并重写Thread类的run方法。

package CounterThread;

public class MyThread extends Thread {
    int count = 1;
    int number;
    public MyThread(int count, int number) {
        this.count = count;
        this.number = number;
        System.out.println("创建线程:" + number);
    }
    // run()方法内的代码是线程的执行内容,这些代码在执行过程中可能被打断执行
    // 因此进行异常处理
    public void run() {
        while (true) {
            System.out.println("线程" + number + ":计数" + count);
            if (++count == 10) {
                return;
            }
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            MyThread myThread = new MyThread(1, i + 1);
            myThread.start();
        }
    }
}

方法二:实现Runnable接口,并重写run方法。

三、线程状态

多线程生命周期:新建、就绪、运行、死亡、 特殊状态存在(睡眠,阻塞,等待)
这里写图片描述

四、线程优先级

线程的优先级表示一个线程被CPU执行的机会的多少。优先级低只说明该线程 被执行的概率小,同理优先级高的线程获得CPU周期的概率大。通过Thread类的setPriority方法设置线程的优先级。

public class MyPriorityThread extends Thread {
    int count = 1;
    int number;
    int priority;

    public MyPriorityThread(int count, int number, int priority) {

        this.count = count;
        this.number = number;
        setPriority(priority);
        System.out.println("创建线程:" + number);
    }

    @Override
    public void run() {
        while (true) {
            System.out.println("线程" + number + ":计数" + count);
            if (++count == 100)
                return;
        }
    }

    public static void main(String[] args) {
        MyPriorityThread myPriorityThread = new MyPriorityThread(1, 3,
                Thread.MAX_PRIORITY);
        myPriorityThread.start();
        for (int i = 0; i < 2; i++) {
            MyPriorityThread myPriorityThread1 = new MyPriorityThread(1, i + 1,
                    Thread.MIN_PRIORITY);
            myPriorityThread1.start();
        }
    }
}

五、线程同步

在多线程中经常遇到的一个问题就是资源共享问题。在多数编程语言中解决共享资源冲突的方法是此采用顺序机制(Serialize)通过为共享资源加锁 的方法实现资源的顺序访问。

为什么存在安全问题?

  1、有共享数据
  2、共享数据被多条 语句操作
  3、在多线程环境中

线程安全问题解决方法

1、同步代码块
synchronized(锁对象){
被同步代码
}

2、同步方法
把 synchronized加在方法上

package SynchronizedThread;

public class FooOne extends Thread {
    private int val;

    public FooOne(int v) {
        val = v;
    }

    // 使用synchronized修饰方法printVal,使得调用该方法的对象获得锁,实现互斥当问
    // 该方法实现无限循环输出一个int型变量
    public synchronized void printVal(int v) {
        while (true)
            System.out.println(v);
    }

    public void run() {
        printVal(val);
    }
}
------------------------------------------------------------------------

package SynchronizedThread;

public class FooTwo extends Thread {
    private FooOne sameFoo;

    // 该类的构造函数传入一个类FooOne的对象引用
    public FooTwo(FooOne f) {
        sameFoo = f;
    }

    public void run() {
        sameFoo.printVal(2);
    }
} ------------------------------------------------------------------------

 package SynchronizedThread;

/**
 * 
 * @author wolfbigbig 
 *  代码分析: 首先创建类FooOne的对象f1,构造函数传入参数1,此时变量val的值为1.通过f1启动线程。
 * 程序执行类FooOne中的run
 * ()的内容,即调用方法printVal()。因为synchronized关键字修饰方法printVal()。
 * 我们称该线程为线程A,则线程A获得FooOne对象f1的锁,而后打印数值1.因为是无限循环,run()方法不会退出。
 * 线程A将不会释放对象f1的锁。
 *
 * 接着程序创建类FooTwo的对象b。此时的构造函数参数为对象引用f1,启动该线程,我们称该线程为线程B。
 * 该线程调用同一个对象f1的synchronized关键字修饰方法printVal()。由于线程A将不会释放对象f1的锁。
 * 所以线程B无法获得对象f1的锁,因此线程B处于阻塞状态。
 *
 * 最后首先创建类FooOne的对象f2。称为线程C。显然f2和f1的锁不同,所以线程C可以获得对象f2的锁。
 *
 * 因此在执行结果上只有线程A和线程C交替执行的输出结果,却永远不会出现线程B的输出。
 */
public class MainTest {
    public static void main(String[] args) {
        // 创建类FooOne的对象,并启动线程
        FooOne f1 = new FooOne(1);
        f1.start();
        // 创建类FooTwo的对象,构造函数参数为类FooOne的对象f1,并启动线程
        FooTwo b = new FooTwo(f1);
        b.start();
        // 创建类FooOne的对象,构造函数参数为3,并启动线程
        FooOne f2 = new FooOne(3);
        f2.start();
    }
}

同步机制锁定的是对象,而不是代码或者函数。只要是不同的对象就有不同的锁。所以函数和代码部分被声明为synchronized并不意味着同一时刻只能有一个线程执行同步资源。

六、线程的控制

Sleep()与Wait()区别

  1. sleep用于线程控制,而wait用于线程间的通信,与wait配套使用的还有notify和notifyAll
  2. sleep是Thread类的方法,是线程用来控制自身流程的,比如有一个要报时的线程,每一秒钟打印出
    一个时间,那么我就需要在print方法前面加一个sleep让自己每隔一秒执行一次。就像闹钟一样
    wait是Object类的方法,用来线程之间的通信,这个方法会使当前拥有该对象锁的进程等待直到其他线程调用notify方法时再醒来。这个方法主要是用于不同线程之间的调度。

3、调用sleep方法不会释放锁。调用wait方法会释放当前线程的锁。

七、死锁问题

由于线程会进入阻塞状态,并且由于对象同步锁的存在,使得只有获得对象锁才能访问该对象,因此很容易发生循环死锁。在编程过程中我们应该避免死锁的出现。

但是在有些面试中会出一些设计死锁的编程题目,现在附上代码一篇。

 package DeadLock;

/**
 * 
 * @author wolfbigbig * 一个简单的死锁: T1:线程1 T2:线程2
 * 当类的对象flag=true时,(T1),先锁定ObjA,然后输出“if objA”,睡眠500毫秒,然后锁定ObjB
 * 而T1在睡眠的时候。T2,先锁定ObjB,然后输出“else objB”,睡眠500毫秒,然后锁定ObjA
 * T1睡眠结束后,需要锁定objB才能继续执行,而此时objB已经被T2锁定。
 * T2睡眠结束后,需要锁定objA才能继续执行,而此时objA已经被T1锁定。
 * T1、T2互相等待,都需要对方锁定的资源才能继续执行,从而形成死锁。
 *
 */
public class DeadLockDemo {
    public static void main(String[] args) {
        // 创建接口对象,用于资源共享、同步
        MyLock ml = new MyLock(true);
        MyLock ml1 = new MyLock(false);

        // 设计两个线程
        Thread t = new Thread(ml);
        Thread t1 = new Thread(ml1);

        t.setPriority(10);
        t1.setPriority(1);
        t.start();
        t1.start();
    }
}
-------------------------------------------------------------
package DeadLock;

public class MyLock implements Runnable {
    public static Object objA = new Object();
    public static Object objB = new Object();
    private boolean flag;

    /*
     * 有参构造函数
     */
    public MyLock(boolean flag) {
        super();
        this.flag = flag;
    }

    public void run() {
        // TODO Auto-generated method stub
        if (flag) {
            synchronized (MyLock.objA) {

                System.out.println("if objA");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                synchronized (MyLock.objB) {
                    System.out.println("if objB");
                }
            }
        } else {
            synchronized (MyLock.objB) {

                System.out.println("else objB");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                synchronized (MyLock.objA) {
                    System.out.println("else objA");
                }
            }
        }
    }
}

多线程为什么比单线程快呢?

多线程为什么比单线程快呢?
  • BigJacky
  • BigJacky
  • 2016年06月05日 12:30
  • 3626

什么是多线程 菜鸟入门

网上很多资料对多线程都有详细的描述与理解,本菜鸟刚刚入门JAVA对多线程方面不是很熟悉,在看过很多视屏,以及相关博客,书籍通过自己的语言来描述对JAVA多线程的理解,给一些和我一样的菜鸟一起交流,写的...
  • x329357842
  • x329357842
  • 2015年12月23日 16:29
  • 5645

《Java多线程编程核心技术》推荐

写这篇博客主要是给猿友们推荐一本书《Java多线程编程核心技术》。之所以要推荐它,主要因为这本书写得十分通俗易懂,以实例贯穿整本书,使得原本抽象的概念,理解起来不再抽象。只要你有一点点Java基础,你...
  • u013142781
  • u013142781
  • 2016年03月04日 21:35
  • 19063

VC编译选项 多线程(/MT) 多线程调试(/MTd) 多线程 DLL (/MD) 多线程调试 DLL (/MDd)

VC编译选项 多线程(/MT) 多线程调试(/MTd) 多线程 DLL (/MD) 多线程调试 DLL (/MDd)
  • vip_member888
  • vip_member888
  • 2017年06月16日 13:27
  • 414

异步与多线程的区别

一、异步和多线程有什么区别? 其实,异步是目的,而多线程是实现这个目的的方法。异步是说,A发起一个操作后(一般都是比较耗时的操作,如果不耗时的操作就没有必要异步了),可以继续自顾自的处理它自己的事儿...
  • zhenghongju
  • zhenghongju
  • 2014年05月05日 09:46
  • 4468

谈谈我对多线程的理解

一、提到多线程,就不得不理解以下几点: 1.程序,进程,线程这三者之间的关系? 简单来说,一程序可以调用多个进程,比如一个视频播放器程序,里面就存在两个进程:一个是播放视频的进程,一个是下载上传视频...
  • DongMeng1994
  • DongMeng1994
  • 2017年01月17日 20:17
  • 3379

多线程是否真的有必要?

相比大家在投简历、面试等等过程中,或多或少会遇到这么一个问题:熟悉掌握多线程开发;谈谈你对多线程的认识。        其实,我有这么一个疑问,那就是多线程真的有必要么?根据我这两年来的项目经验,也...
  • winking324
  • winking324
  • 2014年06月14日 00:09
  • 1391

[006]一步一步学懂spring - spring对多线程支持

我们在使用多线程的时候,往往需要创建Thread类,或者实现Runnable接口,如果要使用到线程池,我们还需要来创建Executors,在使用spring中,已经给我们做了很好的支持。只要要@Ena...
  • king_kgh
  • king_kgh
  • 2017年07月24日 16:17
  • 1068

多线程的文件读写操作讨论

背景: 对于13GB大小的文件,逐行读取,后写到一个新文件。单个线程,进行耗时242s。这里的处理操作比较简单,仅仅是直接写到一个新的文件。如果处理操作耗时越长,多线程的优点越能够显现出来。 采用多线...
  • ljp1919
  • ljp1919
  • 2016年01月08日 11:30
  • 4379

多线程与异步的区别

多线程与异步的区别       随着拥有多个硬线程CPU(超线程、双核)的普及,多线程和异步操作等并发程序设计方法也受到了更多的关注和讨论。本文主要是想与园中各位高手一同探讨一下如何使用并...
  • qq_24541459
  • qq_24541459
  • 2016年06月18日 10:28
  • 2600
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:多线程
举报原因:
原因补充:

(最多只允许输入30个字)