多线程简介
线程的基本知识
线程是程序运行的基本单位,一个程序可以运行多个线程,可以提高程序的运行效率。
线程是具有一定顺序的指令序列,存放方法中定义局部变量的栈和一些共享数据。
线程是相互独立的,任何线程都不能访问其他线程的局部变量。
如果两个线程同时访问一个方法,那每个线程各自得到此方法的一个拷贝。
Java实现线程的两种方式
派生Thread类
实现Runable接口。
创建线程的两种方法
Thread创建线程
/*
继承Thread类创建线程
*/
class MyThread extends Thread{
public MyThread(){}
public MyThread(String name){
super(name);
}
//重载run函数
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(this.currentThread().getName()+"="+i);
}
}
}
//创建线程
public static void main(String[] args) {
//创建线程
MyThread myThread = new MyThread("线程1");
myThread.start();
MyThread myThread1 = new MyThread("线程2");
myThread1.start();
}
实现Runable接口创建线程
/*
实现Runable接口来创建线程
Thread类中有以下两个构造方法:
Thread(Runnable target)
Thread(Runnable target, String name)
*/
class MyRunable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"="+i);
}
}
}
//创建线程
public static void main(String[] args) {
Thread myThread = new Thread(new MyRunable(),"线程1");
myThread.start();
Thread myThread1 = new Thread(new MyRunable(),"线程2");
myThread1.start();
}
等待线程结束
通过isAlive判断
class Main{
public static void main(String[] args) throws InterruptedException {
Thread myThread = new Thread(new MyRunable(),"线程1");
myThread.start();
//判断如果第一个线程在执行,那么让主线程等待,一直执行完线程1之后,再往下执行
while (myThread.isAlive()){
Thread.sleep(1);
}
//执行完线程1,执行线程2
MyThread myThread1 = new MyThread("线程2");
myThread1.start();
}
}
通过join方法
class Main{
public static void main(String[] args) {
Thread myThread = new Thread(new MyRunable(),"线程1");
myThread.start();
/*
join方法
join()-myThread.join()
join(微秒,纳秒)——myThread.join(10,1000)
*/
try {
myThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
//执行完线程1,执行线程2
MyThread myThread1 = new MyThread("线程2");
myThread1.start();
}
}
线程的声明周期
线程的生命周期
线程一共有四种状态:
1. 创建状态
创建在new之后,start之前。
2. 可运行状态
可运行状态在对象执行start之后
3. 不可运行状态
不可运行状态,指线程处于被挂起或者阻塞的状态,例如调用wait()后,线程可能进入阻塞状态;调用线程的notify或者notifyAll后才会再次返回到可运行状态。
4. 退出状态
线程可以在任何状态下调用stop方法进入退出状态,除此之外,线程run完,即执行完也会自动进入退出状态。
线程状态转换
线程状态转换函数
其中stop,suspend和resume方法已经不提倡使用。
suspend由wait方法替代
resume方法由sleep方法替代
线程退出采用自然中止方法,不建议人工调用stop方法。
线程调度(优先级)
多线程应用程序的每个线程的优先级可能不同。
当多个线程等待CPU时间片时,优先级高的能抢占CPU并执行
java中,CPU抢占式的。因此,优先级高的执行的抢占CPU次数较多。
优先级数字1-10
优先级常数:Thread.NORM_PRIORITY,Thread.MAX_PRIORITY,Thread.MIN_PRIORITY
class Main{
public static void main(String[] args) {
Thread myThread = new Thread(new MyRunable(),"线程1");
Thread myThread1 = new Thread(new MyRunable(),"线程2");
myThread.setPriority(10);//设置优先级1-10
// myThread.setPriority(Thread.MAX_PRIORITY);
myThread1.setPriority(1);
// myThread1.setPriority(Thread.MIN_PRIORITY);
myThread.start();
myThread1.start();
}
}
线程的同步
Java应用程序的多线程可以共享资源,当线程以并发模式访问共享数据时,共享数据可能会出现冲突。
java引入线程同步,可以实现共享数据的一致性。
在线程异步的情况下,同一个时刻一个线程修改数据,而另一个线程读取数据,那么读取的数据将会是错误数据。
比如,线程1和线程2都出售火车票,两个线程共享票数,出现以下情况就会出错:
1. 线程1发现票T
2. 线程2发现票T,售出
3. 线程1售出T。
如果线程按照上面顺序出售车票,那么车票T被出售了两次。
java通过sysnchronized关键字锁住共享代码区,从而实现线程同步。
几种同步实现方式
1. 同步方法
class Main{
public static void main(String[] args) {
Acount acount = new Acount();
acount.setCount(100);
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
acount.show();
acount.addMoney(100);
System.out.println("----");
}
}
},"线程1----").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
acount.show();
acount.subMoney(20);
System.out.println("----");
}
}
},"线程2----").start();
}
}
//使用同步方法
class Acount{
private int count;
//存钱
public synchronized void addMoney(int money){
count+=money;
System.out.println("存进="+money+"元");
}
//取钱
public synchronized void subMoney(int money){
count-=money;
System.out.println("取钱="+money+"元");
}
//查询余额
public void show(){
System.out.println("余额="+count+"元");
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
- 同步代码块
class Acount{
private int count;
//存钱
public void addMoney(int money){
synchronized (this) {
count += money;
System.out.println("存进="+money+"元");
}
}
//取钱
public void subMoney(int money){
synchronized (this) {
count -= money;
System.out.println("取钱="+money+"元");
}
}
//查询余额
public void show(){
System.out.println("余额="+count+"元");
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
synchronized关键字
synchronize修饰的方法和 synchronize(this) 都是锁住自己本身的对象 而synchronize(class) synchronize(object) 都是锁别的对象