一、线程的实现方式
方式一:继承Thread类
一个类只要继承了Thread类,并重写run()方法,则就可以实现多线程的操作。

public class ThreadDemo01 {

    public static void main(String[] args) {
Thread1 thread1 = new Thread1("thread1");
Thread2 thread2 = new Thread2("thread2"); System.out.println(thread1.getName());
System.out.println(thread2.getName()); thread1.start();//启动线程
thread2.start();
}
} class Thread1 extends Thread {
public Thread1(String name) {
super(name);
} @Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Thread1 : " + i);
}
}
} class Thread2 extends Thread {
public Thread2(String name) {
super(name);
} @Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Thread2 : " + i);
}
}
}

方式二:实现Runnable接口
一个类只要实现了Runnable类,并重写run()方法,则就可以实现多线程的操作。

public class ThreadDemo03 {

    public static void main(String[] args) {
Thread thread1 = new Thread(new MyThread1(), "thread1");
Thread thread2 = new Thread(new MyThread2(), "thread2"); System.out.println(thread1.getName());
System.out.println(thread2.getName()); thread1.start();//启动线程
thread2.start();
}
} class MyThread1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("MyThread1 :" + i);
}
}
} class MyThread2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("MyThread2 :" + i);
}
}
}

两种启动方式的比较

将我们希望线程执行的代码放到run方法中,然后通过start方法来启动线程,start方法首先为线程的执行准备好系统资源,然后再去调用run方法;

两种方法均需执行线程的start方法为线程分配必须的系统资源,调度线程运行并执行线程的run方法;在使用的时候使用实现接口优先(避免单继承);实现Runnable接口的方式能够实现资源的共享。

二、Thread的JDK源码分析

Thread thread1 = new Thread(new MyThread1(), "thread1");

Thread 构造方法源码如下:

public Thread(String name) {
init(null, null, name, 0);
} public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
} public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
} public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
…..
this.name = name.toCharArray();
this.target = target;
…..
}
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
public void run() {
if (target != null) {
target.run();
}
}

1)当生成一个线程对象时,如果没有为其设定名字,那么线程对象的名字将使用如下形式:Thread-number,该number将是自动增加的,并被所有的Thread对象所共享(因为它是static的成员变量);

2)当使用继承Thread类来生成线程对象时,我们需要重写run()方法,因为Thread类的run()方法此时什么事情都没做(target==null);

3)当使用实现Runnable接口来生成线程对象时,我们需要实现Runnable接口的run()方法,然后使用new Thread(new MyThread())(假使MyThread已经实现了Runnable接口)来生成线程对象,这时的线程对象的run()方法就会调用MyThread类的run方法,这样我们自己编写的run()方法就执行了。

三、线程中成员变量和局部变量的使用

1)如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作时,他们对该成员变量是彼此影响的(也就是说一个线程对成员变量的改变会影响到另一个线程)。

public class ThreadDemo04 {
public static void main(String[] args) {
HelloThread r = new HelloThread();
Thread thread1 = new Thread(r);
Thread thread2 = new Thread(r); thread1.start();
thread2.start();
}
} class HelloThread implements Runnable {
int i; //成员变量 @Override
public void run() {
while (true) {
System.out.println("number: " + this.i++); try {
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
} if (10 == this.i) {
break;
}
}
}
}

结果是:

number: 0
number: 1
number: 2
number: 3
number: 4
number: 5
number: 6
number: 7
number: 8
number: 9

2)如果一个变量是局部变量,那么每个线程都会有一个该局部变量的拷贝,一个线程对该局部变量的改变不会影响到其他的线程。

public class ThreadDemo05 {
public static void main(String[] args) {
WorldThread r = new WorldThread();
Thread thread1 = new Thread(r);
Thread thread2 = new Thread(r); thread1.start();
thread2.start();
}
} class WorldThread implements Runnable { @Override
public void run() {
int i = 0;
while (true) {
System.out.println("number: " + i++); try {
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
if (10 == i) {
break;
}
}
}
}

结果是:

number: 0
number: 0
number: 1
number: 1
……

四、卖票示例

50张票,3个窗口买,每个窗口相当于一个线程。

使用继承Thread类的方式卖票:

class MyThread1 extends Thread {
private Integer num = 50;
public MyThread1(String name) {
super(name);
}
public void run() {
int count = 0;
for (int i = 1; i <= 200; i++) {
if(num > 0){
count ++;
System.out.println(getName() + "卖出第--->" + num-- +"张票");
}
}
System.err.println(getName()+"卖了"+ count +"张票" );
}
}

getName()方法来自于Thread类中,故可以直接获得。

使用实现Runnable的方式卖票:

class MyThread2 implements Runnable{
private Integer num = 50;
public void run() {
int count = 0;
for (int i = 0; i < 200 ; i++) {
if(num > 0){
count ++;
System.out.println(Thread.currentThread().getName()
+ "卖出第--->" + num-- +"张票");
}
}
System.err.println(Thread.currentThread().getName()
+ "卖了"+ count +"张票" );
}
}

由于该类实现了Runnable接口,该接口中并没有获取线程方法名称的方法,故只能采用Thread.currentThread().getName()这种最通用的方法来获得正在执行的线程名称。

两种卖票方式的比较:

继承方式:资源不能共享;一共卖出去150张票,每个窗口各50张;由于继承了Thread类之后就不能再继承其他类了;

接口方式:资源共享;一共卖出去50张票;方便以后扩展。

最新文章

  1. Node基础篇(模块和NPM)
  2. Android 自定义ToolBar详细使用
  3. 机器学习理论知识部分--偏差方差平衡(bias-variance tradeoff)
  4. SQL SERVER 简介及应用 - 数据库系统原理
  5. Shader Overview
  6. 一步步学敏捷开发:4、Scrum的3种角色
  7. IOS开发之不同版本适配问题2(#ifdef __IPHONE_7_0)(转载)
  8. 自定义一个WPF的PathButton
  9. [BEC][hujiang] Lesson04 Unit1:Working life ---Reading + Listening &amp;Grammar &amp; Speaking
  10. Leaflet学习笔记-Leaflet.awesome-markers
  11. 地精排序(Gnome Sort) 算法
  12. ibatis中resultClass与resultMap 的区别
  13. web前端+javascript+h5电子书籍和实战分享
  14. Web 小案例 -- 网上书城(三)
  15. 【6】学习C++之类的实例化及访问
  16. PTA币值转化
  17. 最短路DAG
  18. h5调用qq客户端
  19. 关于 C++ STL
  20. RN中关于IOS和Android的相关权限的问题

热门文章

  1. 对自己的文件使用keystore签名
  2. ARM汇编常用指令
  3. 【转】Redis主从复制简介
  4. eclipse常用插件安装
  5. Builder模式(建造者模式)
  6. c# 对话框交换数据
  7. hibernate级联与反向
  8. DBA_Oracle Archive Log的基本应用和启用(概念)
  9. GL_GL系列 - 日记账处理管理分析(案例)
  10. CF 274B Zero Tree 树形DP