JAVA多线程之——线程的实现方式
来源:互联网 发布:淘宝代充平台 编辑:程序博客网 时间:2024/05/23 18:55
内容转载:http://www.cnblogs.com/skywang12345/p/3479063.html
概要
本章我们学习多线程的两种常用实现方式:继承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 卖票:ticket10Thread-1 卖票:ticket10Thread-2 卖票:ticket10Thread-1 卖票:ticket9Thread-0 卖票:ticket9Thread-1 卖票:ticket8Thread-2 卖票:ticket9Thread-1 卖票:ticket7Thread-0 卖票:ticket8Thread-1 卖票:ticket6Thread-2 卖票:ticket8Thread-1 卖票:ticket5Thread-0 卖票:ticket7Thread-1 卖票:ticket4Thread-2 卖票:ticket7Thread-1 卖票:ticket3Thread-0 卖票:ticket6Thread-1 卖票:ticket2Thread-2 卖票:ticket6Thread-2 卖票:ticket5Thread-2 卖票:ticket4Thread-1 卖票:ticket1Thread-0 卖票:ticket5Thread-2 卖票:ticket3Thread-0 卖票:ticket4Thread-2 卖票:ticket2Thread-0 卖票:ticket3Thread-2 卖票:ticket1Thread-0 卖票:ticket2Thread-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 卖票:ticket10Thread-0 卖票:ticket9Thread-1 卖票:ticket8Thread-0 卖票:ticket7Thread-2 卖票:ticket6Thread-1 卖票:ticket5Thread-2 卖票:ticket4Thread-0 卖票:ticket3Thread-1 卖票:ticket2Thread-2 卖票:ticket1Thread-0 卖票:ticket0Thread-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 卖票:ticket20Thread-2 卖票:ticket19Thread-2 卖票:ticket18Thread-2 卖票:ticket17Thread-2 卖票:ticket16Thread-2 卖票:ticket15Thread-2 卖票:ticket14Thread-2 卖票:ticket13Thread-2 卖票:ticket12Thread-2 卖票:ticket11Thread-1 卖票:ticket10Thread-1 卖票:ticket9Thread-1 卖票:ticket8Thread-1 卖票:ticket7Thread-1 卖票:ticket6Thread-1 卖票:ticket5Thread-1 卖票:ticket4Thread-1 卖票:ticket3Thread-1 卖票:ticket2Thread-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 卖票:ticket20Thread-2 卖票:ticket19Thread-2 卖票:ticket18Thread-2 卖票:ticket17Thread-2 卖票:ticket16Thread-0 卖票:ticket15Thread-0 卖票:ticket14Thread-0 卖票:ticket13Thread-0 卖票:ticket12Thread-0 卖票:ticket11Thread-0 卖票:ticket10Thread-1 卖票:ticket9Thread-0 卖票:ticket8Thread-0 卖票:ticket7Thread-0 卖票:ticket6Thread-0 卖票:ticket5Thread-2 卖票:ticket4Thread-2 卖票:ticket3Thread-2 卖票:ticket2Thread-2 卖票:ticket1
通过声明一个变量,然后在每次卖票判断之前进行加锁。则可以解决这问题。
- JAVA多线程之——线程的实现方式
- Java之旅多线程学习(一)——线程的实现方式
- Java多线程——实现线程的方式以及线程的状态
- Java——多线程的实现方式
- 线程(三)——多线程的实现方式
- 【Java多线程】实现java线程的两种方式
- JAVA单线程以及java多线程的实现方式
- 多线程——Java多线程实现的三种方式
- 多线程——java实现多线程的方式
- java多线程—常用的两种实现多线程方式
- Java多线程:创建线程的两种实现方式
- Java基础:多线程之线程创建的两种方式
- java多线程之创建线程的两种传统方式
- JAVA多线程之线程间的通信方式
- Java多线程基础学习之线程的创建方式总结
- JAVA多线程之线程间的通信方式
- JAVA多线程之线程间的通信方式
- JAVA多线程之线程间的通信方式
- 沉浸式状态栏框架-SystemBarTint
- git常用命令以及使用技巧
- html5与安卓native交互,相互调用
- 【算法】牛客网模拟题编程部分3.23日
- UVA
- JAVA多线程之——线程的实现方式
- ZSTUOJ 4270: 同源数
- 在mac系统安装Apache Tomcat的详细步骤
- [leetcode]83. Remove Duplicates from Sorted List
- Jsp中标签使用:tag 文件方式 和 tld文件方式
- javaScript采用面向对象的方式实现实现拖拽
- jq-$.extend方法使用说明
- JAD-CACHE缓存框架1.0.2版本发布
- UWP入门(十二)--数据绑定用法