JAVA多线程之——线程的实现方式
2017-03-23 23:39
351 查看
内容转载:http://www.cnblogs.com/skywang12345/p/3479063.html
概要
本章我们学习多线程的两种常用实现方式:继承Thread类与实现Runnable接口。
此外我们还可以通过JUC(java.util.concurrent)中的线程池来实现。本章内容包括:
Thread与Runnable简介
Thread 是一个类,而这个类本身就实现了Runnable接口。它的声明如下:
Runnable 是一个接口。该接口中只包含了一个run()方法。它的声明如下:
通过Runnable实现线程:
Thread与Runnable的异同
1.Thread与Runnable都能实现多线程。
2.Thread是类,Runnable是接口。JAVA是单继承,所以Runnable具有更好的扩展性。而Thread本身就实现了Runnable接口。Runnable还可以用于“资源的共享”。即,多个线程都是基于某一个Runnable对象建立的,它们会共享Runnable对象上的资源。
Thread和Runnable的多线程示例
1. Thread的多线程示例
运行结果:
通过Thread启动3个线程去卖票,会导致每个线程都卖出了10张票。
2. Runnable的多线程示例
源博客源代码是这样写的。
**这里代码会有几个问题:
1.就是MyThread 是普通类,而main方法为static方法,在静态方法中,必须将MyThread 声明为静态类。
2.上述代码的执行会导致线程资源竞争出问题。因为3个线程都共享一个对象mt,这样所有线程都竞争mt中的ticket的变量时,可能会出现线程票数为负数。因为当线程1获取最后一张票为1时。如果这个线程还没执行完毕卖票,那么另外一个线程2得到的票数也为1.当线程1卖完票,此时线程2已经获取的为1,此时实际票已经为0.那么得到的结果就会为-1.*
如上代码,在每次卖票之前进行线程休眠。得到结果如下:
如果将ticket变量声明为volatile类型呢?一个变量声明为volatile的原则之一就是该变量计算的值要不依赖前面的值。此处不合适。后面会学习到这个变量此处不详细说明。那么将run方法同步呢?
将run方法同步得到的结果为:
因为如果将整个run方法同步,那么就是锁住mt这个对象,当第一个线程获取了mt的锁之后,后面的线程由于都是共享mt同一个锁,所以,只能等线程1释放该对象的锁。那么,就会导致线程1卖完10张飘。再释放锁。接下来获取mt对象锁的线程再卖10张。这样就等于要一个一个的卖,而不能并发卖。同理声明一个对象obj,在锁住该对象,跟同步run方法运行的结果一致。那该如何呢?
运行结果:
通过声明一个变量,然后在每次卖票判断之前进行加锁。则可以解决这问题。
概要
本章我们学习多线程的两种常用实现方式:继承Thread类与实现Runnable接口。
此外我们还可以通过JUC(java.util.concurrent)中的线程池来实现。本章内容包括:
Thread与Runnable简介
Thread 是一个类,而这个类本身就实现了Runnable接口。它的声明如下:
public class Thread implements Runnable{}
Runnable 是一个接口。该接口中只包含了一个run()方法。它的声明如下:
public interface Runnable { public abstract void run(); }
通过Runnable实现线程:
new Thread(new Runnable(){ @Override public void run() { } });
Thread与Runnable的异同
1.Thread与Runnable都能实现多线程。
2.Thread是类,Runnable是接口。JAVA是单继承,所以Runnable具有更好的扩展性。而Thread本身就实现了Runnable接口。Runnable还可以用于“资源的共享”。即,多个线程都是基于某一个Runnable对象建立的,它们会共享Runnable对象上的资源。
Thread和Runnable的多线程示例
1. Thread的多线程示例
// ThreadTest.java 源码 class MyThread extends Thread{ private int ticket=10; public void run(){ for(int i=0;i<20;i++){ if(this.ticket>0){ System.out.println(this.getName()+" 卖票:ticket"+this.ticket--); } } } }; public class ThreadTest { public static void main(String[] args) { // 启动3个线程t1,t2,t3;每个线程各卖10张票! MyThread t1=new MyThread(); MyThread t2=new MyThread(); MyThread t3=new MyThread(); t1.start(); t2.start(); t3.start(); } }
运行结果:
Thread-0 卖票:ticket10 Thread-1 卖票:ticket10 Thread-2 卖票:ticket10 Thread-1 卖票:ticket9 Thread-0 卖票:ticket9 Thread-1 卖票:ticket8 Thread-2 卖票:ticket9 Thread-1 卖票:ticket7 Thread-0 卖票:ticket8 Thread-1 卖票:ticket6 Thread-2 卖票:ticket8 Thread-1 卖票:ticket5 Thread-0 卖票:ticket7 Thread-1 卖票:ticket4 Thread-2 卖票:ticket7 Thread-1 卖票:ticket3 Thread-0 卖票:ticket6 Thread-1 卖票:ticket2 Thread-2 卖票:ticket6 Thread-2 卖票:ticket5 Thread-2 卖票:ticket4 Thread-1 卖票:ticket1 Thread-0 卖票:ticket5 Thread-2 卖票:ticket3 Thread-0 卖票:ticket4 Thread-2 卖票:ticket2 Thread-0 卖票:ticket3 Thread-2 卖票:ticket1 Thread-0 卖票:ticket2 Thread-0 卖票:ticket1
通过Thread启动3个线程去卖票,会导致每个线程都卖出了10张票。
2. Runnable的多线程示例
源博客源代码是这样写的。
class MyThread implements Runnable{ private int ticket=10; public void run(){ for(int i=0;i<20;i++){ if(this.ticket>0){ System.out.println(Thread.currentThread().getName()+" 卖票:ticket"+this.ticket--); } } } }; public class RunnableTest { public static void main(String[] args) { MyThread mt=new MyThread(); // 启动3个线程t1,t2,t3(它们共用一个Runnable对象),这3个线程一共卖10张票! Thread t1=new Thread(mt); Thread t2=new Thread(mt); Thread t3=new Thread(mt); t1.start(); t2.start(); t3.start(); } }
**这里代码会有几个问题:
1.就是MyThread 是普通类,而main方法为static方法,在静态方法中,必须将MyThread 声明为静态类。
2.上述代码的执行会导致线程资源竞争出问题。因为3个线程都共享一个对象mt,这样所有线程都竞争mt中的ticket的变量时,可能会出现线程票数为负数。因为当线程1获取最后一张票为1时。如果这个线程还没执行完毕卖票,那么另外一个线程2得到的票数也为1.当线程1卖完票,此时线程2已经获取的为1,此时实际票已经为0.那么得到的结果就会为-1.*
public class ThreadTest1 { public static void main(String[] args) { MyThread mt = new MyThread(); // 启动3个线程t1,t2,t3(它们共用一个Runnable对象),这3个线程一共卖10张票! Thread t1 = new Thread(mt); Thread t2 = new Thread(mt); Thread t3 = new Thread(mt); t1.start(); t2.start(); t3.start(); } // RunnableTest.java 源码 static class MyThread implements Runnable { private int ticket = 10; Object obj = new Object(); public void run() { //synchronized (obj) { for (int i = 0; i < 10; i++) { if (this.ticket > 0) { try { Thread.currentThread().sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 卖票:ticket" + this.ticket--); // } } } } //} }; }
如上代码,在每次卖票之前进行线程休眠。得到结果如下:
Thread-2 卖票:ticket10 Thread-0 卖票:ticket9 Thread-1 卖票:ticket8 Thread-0 卖票:ticket7 Thread-2 卖票:ticket6 Thread-1 卖票:ticket5 Thread-2 卖票:ticket4 Thread-0 卖票:ticket3 Thread-1 卖票:ticket2 Thread-2 卖票:ticket1 Thread-0 卖票:ticket0 Thread-1 卖票:ticket-1
如果将ticket变量声明为volatile类型呢?一个变量声明为volatile的原则之一就是该变量计算的值要不依赖前面的值。此处不合适。后面会学习到这个变量此处不详细说明。那么将run方法同步呢?
public class ThreadTest1 { public static void main(String[] args) { MyThread mt = new MyThread(); // 启动3个线程t1,t2,t3(它们共用一个Runnable对象),这3个线程一共卖10张票! Thread t1 = new Thread(mt); Thread t2 = new Thread(mt); Thread t3 = new Thread(mt); t1.start(); t2.start(); t3.start(); } // RunnableTest.java 源码 static class MyThread implements Runnable { private int ticket = 20; Object obj = new Object(); public synchronized void run() { //synchronized (obj) { for (int i = 0; i < 10; i++) { if (this.ticket > 0) { try { Thread.currentThread().sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 卖票:ticket" + this.ticket--); // } } } } //} }; }
将run方法同步得到的结果为:
Thread-2 卖票:ticket20 Thread-2 卖票:ticket19 Thread-2 卖票:ticket18 Thread-2 卖票:ticket17 Thread-2 卖票:ticket16 Thread-2 卖票:ticket15 Thread-2 卖票:ticket14 Thread-2 卖票:ticket13 Thread-2 卖票:ticket12 Thread-2 卖票:ticket11 Thread-1 卖票:ticket10 Thread-1 卖票:ticket9 Thread-1 卖票:ticket8 Thread-1 卖票:ticket7 Thread-1 卖票:ticket6 Thread-1 卖票:ticket5 Thread-1 卖票:ticket4 Thread-1 卖票:ticket3 Thread-1 卖票:ticket2 Thread-1 卖票:ticket1
因为如果将整个run方法同步,那么就是锁住mt这个对象,当第一个线程获取了mt的锁之后,后面的线程由于都是共享mt同一个锁,所以,只能等线程1释放该对象的锁。那么,就会导致线程1卖完10张飘。再释放锁。接下来获取mt对象锁的线程再卖10张。这样就等于要一个一个的卖,而不能并发卖。同理声明一个对象obj,在锁住该对象,跟同步run方法运行的结果一致。那该如何呢?
import java.util.concurrent.atomic.AtomicInteger; public class ThreadTest1 { public static void main(String[] args) { MyThread mt = new MyThread(); // 启动3个线程t1,t2,t3(它们共用一个Runnable对象),这3个线程一共卖10张票! Thread t1 = new Thread(mt); Thread t2 = new Thread(mt); Thread t3 = new Thread(mt); t1.start(); t2.start(); t3.start(); } // RunnableTest.java 源码 static class MyThread implements Runnable { private int ticket = 20; Object obj = new Object(); public void run() { for (int i = 0; i < 10; i++) { synchronized (obj) { if (ticket > 0) { try { Thread.currentThread().sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 卖票:ticket" + this.ticket--); } } } } //} }; }
运行结果:
Thread-2 卖票:ticket20 Thread-2 卖票:ticket19 Thread-2 卖票:ticket18 Thread-2 卖票:ticket17 Thread-2 卖票:ticket16 Thread-0 卖票:ticket15 Thread-0 卖票:ticket14 Thread-0 卖票:ticket13 Thread-0 卖票:ticket12 Thread-0 卖票:ticket11 Thread-0 卖票:ticket10 Thread-1 卖票:ticket9 Thread-0 卖票:ticket8 Thread-0 卖票:ticket7 Thread-0 卖票:ticket6 Thread-0 卖票:ticket5 Thread-2 卖票:ticket4 Thread-2 卖票:ticket3 Thread-2 卖票:ticket2 Thread-2 卖票:ticket1
通过声明一个变量,然后在每次卖票判断之前进行加锁。则可以解决这问题。
相关文章推荐
- JAVA多线程之——线程的实现方式
- JAVA多线程之——线程的实现方式
- Java第七课 Java的多线程程序进程和线程的概念,实现多线程的两种方式,线程同步的原理,线程的死锁,运用wait和notify来实现producer - consumer关系,线程终止的两种情况。
- Java_基础—多线程(匿名内部类实现线程的两种方式和设置名字的方法)
- JAVA多线程之——线程的实现方式
- JAVA多线程之——线程的实现方式
- 用java传统线程方式实现多线程轮询执行问题
- Java多线程学习笔记1——线程的实现方式以及定时器的使用
- 总结Java中线程的状态及多线程的实现方式
- JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没
- JAVA多线程之——线程的实现方式
- JAVA多线程之——线程的实现方式
- JAVA多线程之——线程的实现方式
- JAVA多线程之——线程的实现方式
- Java【多线程知识总结(5)】比较继承Thread类创建线程和实现Runnable接口创建线程这两种方式
- Java多线程——实现线程的方式以及线程的状态
- JAVA多线程之——线程的实现方式
- java多线程 -- 创建线程的第三者方式 实现Callable接口
- Java【多线程知识总结(5)】比较继承Thread类创建线程和实现Runnable接口创建线程这两种方式
- JAVA多线程之——线程的实现方式