1、Thread类
package com.wjl.base;
public class MyThread extends Thread {
/**
* 利用继承的特点
* 将线程名称传递
* @param name
*/
public MyThread(String name) {
super(name);
}
public void run() {
for(int i=0;i<20;i++) {
//getName来自父类Thread
System.out.println(getName()+"--"+i+"---");
}
}
}
测试
package com.wjl.test;
import com.wjl.base.MyThread;
/**
* 多线程
* @author wjl
*
*/
public class Demo01 {
public static void main(String[] args) {
/*
* 多线程执行时,在栈内存中,每个执行线程都有一片自己所属的栈内存空间。
* 进行方法的压栈和弹栈。
*/
MyThread mt=new MyThread("业务1");
mt.start();//开启一个新的线程
for(int i=0;i<20;i++) {
System.out.println("主线程"+"---"+i+"----");
}
}
}
Thread构造方法:
- public Thread() 分配一个新的线程对象。
- public Thread(String name) 分配一个指定名字的新的线程对象。
- public Thread(Runnable target) 分配一个带有指定目标新的线程对象。
- public Thread(Runnable target,String name) 分配一个带有指定目标新的线程对象并指定名字
常用方法:
- public String getName() :获取当前线程名称。
- public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。
- public void run() :此线程要执行的任务在此处定义代码。
- public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
- public static Thread currentThread() :返回对当前正在执行的线程对象的引用。
2、Runnable
public class MyRunnabe implements Runnable {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"---"+i+"---");
}
}
}
import com.wjl.base.MyRunnabe;
public class Demo02 {
public static void main(String[] args) {
MyRunnabe mr=new MyRunnabe();
//创建线程对象
Thread thread=new Thread(mr, "业务2");
thread.start();
for (int i = 0; i < 20; i++) {
System.out.println("主线程"+"---"+i+"----");
}
}
}
3、Thread和Runnable的区别
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
总结:
实现Runnable接口比继承Thread类所具有的优势:
- 适合多个相同的程序代码的线程去共享同一个资源。
- 可以避免java中的单继承的局限性。
- 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
- 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类
4、线程同步
4.1 同步代码块
同步代码块: synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
格式:
synchronized(同步锁){
需要同步操作的代码
}
同步锁:
对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.
1. 锁对象 可以是任意类型。
2. 多个线程对象 要使用同一把锁
/**
* 同步代码块
* @author wjl
*
*/
public class Ticket implements Runnable {
private int ticket=100;
Object lock=new Object();
//执行卖票操作
@Override
public void run() {
while(true) {
synchronized (lock) {
if(ticket>0) {//有票
try {
Thread.sleep(100);//模拟出票时间
} catch (Exception e) {
e.printStackTrace();
}
//获取当前线程的名字
String name=Thread.currentThread().getName();
System.out.println(name+" 正在售"+ticket--+"---");
}else {
break;
}
}
}
}
}
测试
package com.wjl.test;
import com.wjl.ticket.Ticket;
public class Demo03Ticket1 {
public static void main(String[] args) {
Ticket ticket=new Ticket();
Thread t1=new Thread(ticket,"窗口1");
Thread t2=new Thread(ticket,"窗口2");
Thread t3=new Thread(ticket,"窗口3");
//同时卖票
t1.start();
t2.start();
t3.start();
}
}
4.2 同步方法
同步方法:使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着
public synchronized void method(){
可能会产生线程安全问题的代码
}
package com.wjl.ticket;
public class Ticket2 implements Runnable {
private int ticketNum=100;
@Override
public void run() {
while(true) {
sellTicekt();
}
}
/**
* 锁对象 是 谁调用这个方法 就是谁
* 隐含 锁对象 就是 this
*/
public synchronized void sellTicekt() {
if(ticketNum>0) {//有票
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
//获取当前线程对象的名字
String name=Thread.currentThread().getName();
System.out.println(name+" 正在售"+ticketNum--+"---");
}
}
}
4.3 Lock锁
java.util.concurrent.locks.Lock 机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。
Lock锁也称同步锁,加锁与释放锁方法化了,如下:
- public void lock() :加同步锁。
- public void unlock() :释放同步锁。
使用如下
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Ticket3 implements Runnable{
private int ticketNum=100;
Lock lock=new ReentrantLock();
@Override
public void run() {
while(true) {
lock.lock();
if(ticketNum>0) {//有票
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
//获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name+"正在售"+ticketNum--+"---");
}
lock.unlock();
}
}
}
5、线程状态
在API中 java.lang.Thread.State 这个枚举中给出了六种线程状态: