java多线程

Posted 编程语言之旅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java多线程相关的知识,希望对你有一定的参考价值。

Java实现多线程方式有两种:继承Thread类或者实现Runnable即可.线程启动时调用start()方法. 
实现Runnable接口可以实现资源共享 
下面让我们来看一下代码:

public class Thread1 extends Thread{

    private int num = 5;    @Override
    public void run() {        for(int i=0;i<10;i++)
        {            if(this.num>0)
            {
                System.out.println("剩余的票1:"+num--);
            }
        }
    }

}public class Thread2 implements Runnable{

    private int num = 5;    public void run() {        for(int i=0;i<10;i++)
        {            if(this.num>0){
                System.out.println("剩余的票2:"+num--);
            }
        }
    }

}    /**     * @author 付玉伟     * @time 2015-4-9 下午09:37:56     * @param args     */
    public static void main(String[] args) {
        Thread1 t1 = new Thread1();
        t1.setName("售票窗口1");
        Thread1 t2 = new Thread1();

        t1.setName("售票窗口2");
        Thread1 t3 = new Thread1();
        t1.setName("售票窗口3");

        t1.start();
        t2.start();
        t3.start();


        Thread2 t1_ = new Thread2();
        Thread t1_1 = new Thread(t1_);
        t1_1.setName("售票窗口1_");

        Thread t2_2 = new Thread(t1_);
        t2_2.setName("售票窗口2_");

        Thread t3_3 = new Thread(t1_);
        t1_1.setName("售票窗口3_");

        t1_1.start();
        t2_2.start();
        t3_3.start();
    }

}
 
   
   
 
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49

  • 50

  • 51

  • 52

  • 53

  • 54

  • 55

  • 56

  • 57

  • 58

  • 59

  • 60

  • 61

  • 62

  • 63

  • 64

  • 65

  • 66

  • 67

  • 68

运行结果如下: 
 
一共5张票,线程1卖了15次,显然资源没有共享,而线程2只买了5次。 
Java多线程访问共享资源的方式: 
1、如果每一个线程执行的代码相同,可以使用同一个runnable对象,这个对象中有那个共享数据(买票系统) 
2、如果每一个线程执行的代码不相同,这时候需要不同的Runnable对象,有以下两种方式来实现这些Runnable对戏之间的数据共享。 
(1)、将共享数据封装在另外一个对象中,然后将这个对象逐一传递给各个Runnable对象。每个线程对共享数据的操作方法也分配到那个对象身上去完成,这样容易实现针对该数据进行的各个操作的互斥和通信。 
  (2)、将这些Runnable对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方法也分配给外部类,以便实现对共享数据进行的各个操作的互斥和通信,作为内部类的各个Runnable对象调用外部类的这些方法。 
  (3)、上面两种方式的组合:将共享数据封装在另外一个对象中,每个线程对共享数据的操作方法也分配到那个对象身上去完成,对象作为这个外部类中的成员变量或方法中的局部变量,每个线程的Runnable对象作为外部类中的成员内部类或局部内部类。 
  (4)、总之,要同步互斥的几段代码最好是分别放在几个独立的方法中,这些方法再放在同一个类中,这样比较容易实现它们之间的同步互斥和通信。 
3、极端且简单的方式,即在任意一个类中定义一个static的变量,这将被所有线程共享 
在线程操作中由于其操作的不确定性,所以提供了一个方法,可以取得当前操作线程: 
public static Thread currentThread(); 
说明: 
对于线程的名字一般是在启动前进行设置,最好不要设置相同的名字,最好不要为一个线程改名字. 
在Java执行中一个Java程序至少启动2个线程:一个主线程和一个垃圾回收线程. 
多线程的同步问题 
如果使用Runnable的方式实现买票系统,在买票出现延迟时如:

public class Thread2 implements Runnable{

    private int num = 5;    public void run() {        for(int i=0;i<10;i++)
        {            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }            if(this.num>0){
                System.out.println("剩余的票2:"+num--);
            }
        }
    }

}
 
   
   
 
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

输出结果如下: 
 
如果解决这样的问题就必须使用同步,即:过个操作在同一个时间段内只有一个线程进行。 
Java多线程同该方法步主要依赖于若干方法和关键字 
1、wait方法 
Object的方法,作用是使得当前调用wait方法所在部分的线程停止执行,并释放当前所获得调用wait的代码块的锁,并在其他线程调用notify或者notifyAll方法时恢复到竞争锁状态 
wait被调用的时候必须在拥有锁(synchronized修饰)的代码块中 
恢复执行后,从wait的下一条语句开始执行,因为wait方法总是应当在while循环中调用,以免出现恢复执行后继续执行的条件却不满足继续执行的条件。 
若wait方法参数中带时间,则除了notify和notifyAll被调用能激活处于wait状态的线程进入锁竞争外,在其他线程中interrupt它或者参数时间到了之后,该线程也将激活到竞争状态。 
wait方法被调用的线程必须获得之前执行到wait时释放掉用的锁重新获得才能够恢复执行。 
2、notify方法和notifyAll方法 
notify方法通过调用了wait方法,但是尚未激活一个线程调度队列(即进入竞争锁),不是立即执行。并且具体是哪一个线程不能保证。另外一点就是被唤醒的这个线程一定是等待wait所释放的锁。 
notifyAll方法则唤醒所有调用wait方法,尚未激活的进程进入竞争队列。 
3、synchronized关键字 
用来标识一个普通方法时,表示一个线程要执行该方法必须取得该方法所在对象的锁。 
用来 标识一个静态方法时,表示一个线程要执行该方法必须取得该方法所在类的类锁 
修饰一个代码块。类似synchronized(Obj){}表示一个线程要执行的代码块必须获得Object的锁,这样做的目的是减小锁的粒度,保证当不同块所需的锁不冲突时不用对整个对象加锁。利用零长度的byte数组对象做obj非常经济。 
4、atomic action 原子操作 
在Java中,以下都是原子操作,但是在C和C++中不是 
对引用变量和除了long和double之外的原始数据类型变量进行读写 
对所有声明为volatile的变量(包括long和double)的读写 
另外在Java.util.concurrent和java.util.concurrent.atomic包中提供了一些不依赖于同步机制的线程安全类和方法。 
下面使用synchronized来解决同步的问题: 
1、同步代码块

public class Thread2 implements Runnable{

    private int num = 5;    public void run() {        for(int i=0;i<10;i++)
        {            // 使用同步代码块
            synchronized(this){                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }            if(this.num>0){
                System.out.println("剩余的票2:"+num--);
            }
        }
    }

}
 
   
   
 
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

2、同步方法

public class Thread3 implements Runnable{

    private int num = 5;    public void run() {        for(int i=0;i<10;i++){
            sale();
        }
    }    // 使用同步方法
    public synchronized void sale(){        try {
            Thread.sleep(300);    //休息300毫秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        } 
        if(num > 0 ){
            System.out.println(Thread.currentThread().getName()+"买票"+this.num--);
        }
    }    public static void main(String[] args){
        Thread3 t3 = new Thread3();        new Thread(t3,"售票窗口1").start();        new Thread(t3,"售票窗口2").start();        new Thread(t3,"售票窗口3").start();
    }
}
 
   
   
 
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

多线程之间资源共享需要使用同步,但是过多的同步会造成死锁。 
死锁是在多道程序系统中,一组进程中的每一个进程都无限期的等待另一个线程,所以占有且永远不会释放的资源。 
死锁产生的原因: 
1、竞争资源,系统提供的资源有限,不能满足每一个进程的要求 
2、多道程序运行时,进程推进顺序不合理 
产生死锁的必要条件: 
1、互斥资源使用 
2、占用并等待资源 
3、不可抢夺资源 
4、循环等待资源


以上是关于java多线程的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程与并发库高级应用-工具类介绍

多线程 Thread 线程同步 synchronized

Java多线程具体解释

自己开发的在线视频下载工具,基于Java多线程

什么是JAVA的多线程?

多个用户访问同一段代码