什么是线程
进程是指可执行程序放在计算机存储器的一个指令序列,他是一个动态执行的过程。
线程是比进程还要小的单位,一个进程包含多个线程,线程可以看做一个子程序
Thread类和Runnable接口介绍
《Thread类常用构造方法,位于java.lang包》
构造方法
Thread()
创建一个线程对象
Thread(String name)
创建一个具有指定名称的线程对象
Thread(Runnable target)
创建一个基于Runnable接口实现类的线程对象
Thread(Runnable target, String name)
创建一个基于Runnable接口实现类,并且具有指定民称的线程对象
《Thread类常用方法》
public void run():线程相关的代码写在该方法中,一般需要重写
public void start():启动线程的方法
public static void sleep(long m):线程休眠m毫秒的方法
public void join():优先执行调用join()方法的线程
《Runnable接口》
只有一个方法run();
Runnable是Java中用以实现线程的接口
任何实现线程功能的类都必须实现该接口

通过Thread类创建线程(上)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package com.imooc.thread; class MyThread extends Thread{ public void run(){ System.out.println(getName()+"该线程正在执行!"); } } public class ThreadTest {
public static void main(String[] args) { MyThread mt=new MyThread(); mt.start(); mt.start();
}
}
|
1、一个java源文件中,可以并存多个独立的类(非内部类),但是只能有一个public类,且public类类名与文件名相同。
2、启动线程:
MyThread mt = new MyThread();
mt.start();
注:一个线程只能启动一次,start()只能调用一次。多次调用会产生IllegalThreadStateException异常。
3、主方法本身也会产生一个线程。其和其他线程运行顺序是随机的。
通过Thread类创建线程(下)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package com.imooc.thread1; class MyThread extends Thread{ public MyThread(String name){ super(name); } public void run(){ for(int i=1;i<=10;i++){ System.out.println(getName()+"正在运行"+i); } } } public class ThreadTest {
public static void main(String[] args) { MyThread mt1=new MyThread("线程1"); MyThread mt2=new MyThread("线程2"); mt1.start(); mt2.start(); }
}
|
通过此例子可以看出,线程获得CPU的使用权是随机的

实现Runnable接口创建线程
通过实现Runnable接口的方式来实现线程:(现实工作中用的更多)
存在这个方式的原因:
1:如果一个类继承了其他类,就没办法继承Thread类了。只有实现runnable来创建线程;
2:thread中有很多的方法,不打算继承除了run方法外的其他方法,那么只实现Runnable后重写run方法就行了。
使用方式:在一个类中实现接口,然后根据需求重写run方法。
在调用时,需要先实例化实现run方法的类a,再把a做参数实例化Thread类b。然后用b.start()来启动线程。
这里的Runnable对象可以被多个线程公用,即多个Thread实例化都可以调用同一个对象作为参数。
注:run方法中很大概率使用Thread.currentThread().getName()来获取线程名。(因为Runnable接口中只有一个run方法);

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
| package com.imooc.runnable;
class PrintRunnable implements Runnable { int i = 1; @Override public void run() {
while (i <= 10) System.out.println(Thread.currentThread().getName() + "正在运行" + (i++)); }
}
public class Test {
public static void main(String[] args) { PrintRunnable pr = new PrintRunnable(); Thread t1 = new Thread(pr); t1.start(); Thread t2 = new Thread(pr); t2.start();
}
}
|
线程的状态和生命周期

sleep方法的使用
sleep:
是thread的方法:public static void sleep(long millis)
作用是让正在执行的线程休眠指定的毫秒数,之后重新变为可运行状态。参数是休眠的时间,单位是毫秒。
在run方法中调用时,使用Thread.sleep(xxx);
调用sleep()方法,需要进行异常处理。调用try catch。
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
| package com.imooc.sleep;
class MyThread implements Runnable{
@Override public void run() { for(int i=1;i<=30;i++){ System.out.println(Thread.currentThread().getName()+"执行第"+i+"次!"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
} public class SleepDemo {
public static void main(String[] args) { MyThread mt=new MyThread(); Thread t=new Thread(mt); t.start(); Thread t1=new Thread(mt); t1.start(); }
}
|
编程练习1
利用线程输出“a~z”的26个字母(横向输出),要求每隔一秒钟输出一个字母
效果图:

(每隔一秒钟输出一个字母)
任务要求:
创建实现类Letter,它实现Runnable接口
定义一个char类型的数组letter[ ]来存放26个字母
方法:1)创建无参构造方法对数组中元素进行循环赋值。
2)重写run( )方法,再建立一个循环,循环中实现每隔一秒打印输出一个字母。
2、创建测试类,创建Letter类的对象,再通过Letter类的对象创建线程类的对象,然后启动线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package me.feihong.thread;
class Letter implements Runnable{ char[] letter=new char[26]; public Letter() { for(int i=0;i<letter.length;i++) { letter[i]=(char)(97+i); } } @Override public void run() { for(int i=0;i<letter.length;i++) { System.out.print(letter[i]+" "); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }
}
}
|
1 2 3 4 5 6 7 8 9 10 11 12
| package me.feihong.thread;
public class words {
public static void main(String[] args) { Letter le=new Letter(); Thread t1=new Thread(le); t1.start(); }
}
|
join方法的使用
join方法的第二种用法,当输入的毫秒时间结束时,使用join()方法的线程不管是否运行结束,CPU继续执行其他线程

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
| package com.imooc.join;
class MyThread extends Thread{ public void run(){ for(int i=1;i<=500;i++) System.out.println(getName()+"正在执行"+i+"次!"); } } public class JoinDemo {
public static void main(String[] args) { MyThread mt=new MyThread(); mt.start(); try { mt.join(1); } catch (InterruptedException e) { e.printStackTrace(); } for(int i=1;i<=20;i++){ System.out.println("主线程运行第"+i+"次!"); } System.out.println("主线程运行结束!"); }
}
|
线程的优先级
Java为线程提供了10个优先级
优先级可以用整数1-10表示,超过范围会抛出异常。
主线程默认优先级为5,数字越大优先级别越高
优先级常量
MAX_PRIORITY : 线程的最高优先级10
MIN_PRIORITY : 线程的最低优先级1
NORM_PRIORITY : 线程的默认优先级5
优先级相关的方法
public int getPriority() 获取线程优先级的方法
public void setPriority(int newPriority) 设置线程优先级的方法

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
| package com.imooc.priority;
class MyThread extends Thread{ private String name; public MyThread(String name){ this.name=name; } public void run(){ for(int i=1;i<=50;i++){ System.out.println("线程"+name+"正在运行"+i); } } } public class PriorityDemo {
public static void main(String[] args) { int mainPriority=Thread.currentThread().getPriority(); MyThread mt1=new MyThread("线程1"); MyThread mt2=new MyThread("线程2"); mt1.setPriority(Thread.MAX_PRIORITY); mt2.setPriority(Thread.MIN_PRIORITY); mt2.start(); mt1.start(); }
}
|
线程同步
多线程的运行问题
1.各个线程是通过竞争cpu时间而获得运行机会的
2.各线程什么时候得到cpu时间,占用多久,是不可预测的
3.一个正在运行着的线程在什么地方被暂停是不确定的
synchronized关键字,可以用在:成员方法,静态方法,语句块,将其锁定,确保共享对象在同一时刻只能被一个线程访问,这种机制称为线程的同步

银行存取款案例:
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 69 70 71 72 73
| package com.imooc.bank;
public class Bank { private String account; private int balance;
public Bank(String account, int balance) { this.account = account; this.balance = balance; }
public String getAccount() { return account; }
public void setAccount(String account) { this.account = account; }
public int getBalance() { return balance; }
public void setBalance(int balance) { this.balance = balance; }
@Override public String toString() { return "Bank [账号:" + account + ", 余额:" + balance + "]"; }
public synchronized void saveAccount() {
int balance = getBalance(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } balance += 100; setBalance(balance); System.out.println("存款后的账户余额为:" + balance); }
public void drawAccount() { synchronized (this) {
int balance = getBalance(); balance = balance - 200; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } setBalance(balance); System.out.println("取款后的帐户余额:" + balance); }
}
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com.imooc.bank;
public class DrawAccount implements Runnable{ Bank bank; public DrawAccount(Bank bank){ this.bank=bank; } @Override public void run() { bank.drawAccount(); } }
|
1 2 3 4 5 6 7 8 9 10 11
| package com.imooc.bank;
public class SaveAccount implements Runnable{ Bank bank; public SaveAccount(Bank bank){ this.bank=bank; } public void run(){ bank.saveAccount(); } }
|
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
| package com.imooc.bank;
public class Test {
public static void main(String[] args) { Bank bank=new Bank("1001",1000); SaveAccount sa=new SaveAccount(bank); DrawAccount da=new DrawAccount(bank); Thread save=new Thread(sa); Thread draw=new Thread(da); save.start(); draw.start(); try { draw.join(); save.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(bank); }
}
|
线程间通信
线程见通信:
三个Object类的方法:(都被继承了,可直接使用)
wait()方法:中断方法的执行,使线程处于等待状态:(阻塞);
notify()方法:唤醒处于等待的某一个线程,使其进入可运行状态;
notifyAll()方法:唤醒所有的处于等待的线程,进入可运行状态;一般使用notifyAll()方法比较多。
wait方法需要进行异常处理;

案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.imooc.queue;
public class Consumer implements Runnable{ Queue queue; Consumer(Queue queue){ this.queue=queue; }
@Override public void run() { while(true){ queue.get(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.imooc.queue;
public class Producer implements Runnable{ Queue queue; Producer(Queue queue){ this.queue=queue; }
@Override public void run() { int i=0; while(true){ queue.set(i++); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
}
|
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
| package com.imooc.queue;
public class Queue { private int n; boolean flag=false;
public synchronized int get() { if(!flag){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("消费:"+n); flag=false; notifyAll(); return n; }
public synchronized void set(int n) { if(flag){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("生产:"+n); this.n = n; flag=true; notifyAll(); }
}
|
1 2 3 4 5 6 7 8 9 10 11
| package com.imooc.queue;
public class Test {
public static void main(String[] args) { Queue queue=new Queue(); new Thread(new Producer(queue)).start(); new Thread(new Consumer(queue)).start(); }
}
|