线程创建主要有两种创建方式:
继承Thread类方式:
public class ThreadTest {
public static void main(String[] args) {
MyThread mt = new MyThread(); //实例化子线程
mt.start(); //子线程进入就绪态
for (int i = 0; i < 5; i++){ //执行主线程逻辑
System.out.println("主线程的第" + (i + 1) + "次执行");
try{
Thread.sleep(50);
}catch (InterruptedException e){
System.out.println("Main thread interrupted");
}
}
}
}
class MyThread extends Thread{ //继承Thread类
@Override
public void run(){ //需要重写run方法
for (int i = 0; i < 5; i++){ //执行子线程逻辑
System.out.println("子线程的第" + (i + 1) + "次执行");
try{
Thread.sleep(50);
}catch (InterruptedException e){
System.out.println("Child thread interrupted");
}
}
}
}
代码执行结果:
主线程的第1次执行
子线程的第1次执行
主线程的第2次执行
子线程的第2次执行
主线程的第3次执行
子线程的第3次执行
主线程的第4次执行
子线程的第4次执行
主线程的第5次执行
子线程的第5次执行
实现Runable接口方式:
public class ThreadTest {
public static void main(String[] args) {
MyThread mt = new MyThread(); //实例化子线程
for (int i = 0; i < 5; i++){ //执行主线程逻辑
System.out.println("主线程的第" + (i + 1) + "次执行");
try{
Thread.sleep(50);
}catch (InterruptedException e){
System.out.println("Main thread interrupted");
}
}
}
}
class MyThread implements Runnable{ //实现Runable接口
Thread t; //需要使用一个Thread对象
public MyThread(){
t = new Thread(this); //在自定义线程类的构造方法中实例化这个Thread对象
t.start(); //并给予执行
}
@Override
public void run(){ //并重写run方法
for (int i = 0; i < 5; i++){ //执行子线程逻辑
System.out.println("子线程的第" + (i + 1) + "次执行");
try{
Thread.sleep(50);
}catch (InterruptedException e){
System.out.println("Child thread interrupted");
}
}
}
}
代码执行结果:
主线程的第1次执行
子线程的第1次执行
主线程的第2次执行
子线程的第2次执行
主线程的第3次执行
子线程的第3次执行
主线程的第4次执行
子线程的第4次执行
主线程的第5次执行
子线程的第5次执行
注意: 为了提高代码的可扩展性,一般情况下我们通常使用实现Runable接口的方式来创建子线程。因为Java的单根继承特性,若该线程类继承了Thread类,则无法继承其他自定义的类。
Thread t = new Thread("Child_1")
;Thread t = new Thread();
t.setName("Child_1");
方法3:对于自定义的线程类,可以借用父类的构造方法来命名。如:class MyThread extends Thread{
public MyThread(String name){
super(name);
}
}
@Override
public void run(){
for (int i = 0; i < 5; i++){
System.out.println("子线程的第" + (i + 1) + "次执行");
try{
Thread.sleep(50);//单位是毫秒
}catch (InterruptedException e){
System.out.println("Child thread interrupted");
}
}
}
Thread t = new Thread();
t.setPriority(9);//设置线程t的优先级为9
@Override
public static void run(){
for(int i = 0; i < 10; i++){
if(i == 3){
Thread.yield();//让出当前线程的CPU使用权
}
}
}
public class TicketCenter {
public static int tickets = 8;
public static void main(String[] args) {
//实例化4个售票员
Conductor conductor1 = new Conductor("1号售票员");
Conductor conductor2 = new Conductor("2号售票员");
Conductor conductor3 = new Conductor("3号售票员");
Conductor conductor4 = new Conductor("4号售票员");
}
}
class Conductor implements Runnable{//售票员类
Thread t;
public Conductor(String name){
t = new Thread(this,name);
t.start();
}
@Override
public void run(){//售票逻辑
while (TicketCenter.tickets > 0){
System.out.println(Thread.currentThread().getName() + "卖出1张票,剩余" + --TicketCenter.tickets + "张票");
}
try {
Thread.sleep(10);//模拟售票过程中消耗的时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
代码执行结果:1号售票员卖出1张票,剩余6张票
1号售票员卖出1张票,剩余3张票
1号售票员卖出1张票,剩余2张票
1号售票员卖出1张票,剩余1张票
1号售票员卖出1张票,剩余0张票
3号售票员卖出1张票,剩余4张票
4号售票员卖出1张票,剩余7张票
2号售票员卖出1张票,剩余5张票
显然不符合实际情况。因为在本例中tickets属于临界资源,四个Conductor线程同时访问了临界资源,所以会产生意想不到的结果。 public class TicketCenter {
public static int tickets = 10;
public static void main(String[] args) {
//实例化4个售票员
Conductor conductor1 = new Conductor("1号售票员");
Conductor conductor2 = new Conductor("2号售票员");
Conductor conductor3 = new Conductor("3号售票员");
Conductor conductor4 = new Conductor("4号售票员");
}
}
class Conductor implements Runnable{
Thread t;
public Conductor(String name){
t = new Thread(this,name);
t.start();
}
@Override
public void run(){
while (TicketCenter.tickets > 0){
synchronized (TicketCenter.class){//定义锁标记,抢到锁标记的线程进入代码块,未抢到的线程则进入锁池(线程阻塞),等待解锁后再争抢锁标记
//需要注意的是。上面小括号里面的锁标记是对象锁或者类锁都行,只要保证所有线程争抢的是同一把锁即可
if (TicketCenter.tickets <= 0){//判断tickets的情况,也就是双重检查的思想
return;
}
System.out.println(Thread.currentThread().getName() + "卖出1张票,剩余" + --TicketCenter.tickets + "张票");
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
代码执行结果:1号售票员卖出1张票,剩余9张票
2号售票员卖出1张票,剩余8张票
3号售票员卖出1张票,剩余7张票
4号售票员卖出1张票,剩余6张票
2号售票员卖出1张票,剩余5张票
1号售票员卖出1张票,剩余4张票
4号售票员卖出1张票,剩余3张票
3号售票员卖出1张票,剩余2张票
2号售票员卖出1张票,剩余1张票
1号售票员卖出1张票,剩余0张票
public class TicketCenter {
public static int tickets = 10;
public static void main(String[] args) {
//实例化4个售票员
Conductor conductor1 = new Conductor("1号售票员");
Conductor conductor2 = new Conductor("2号售票员");
Conductor conductor3 = new Conductor("3号售票员");
Conductor conductor4 = new Conductor("4号售票员");
}
}
class Conductor implements Runnable{
Thread t;
public Conductor(String name){
t = new Thread(this,name);
t.start();
}
public static synchronized void soldTicket(){//设置同步方法,与同步代码段类似
//若此方法为静态,则设置的锁为类锁:Conductor.class
//若此方法不为静态,则设置的锁为对象锁:this,当然此处并不适用,因为此时this指向不同的Conductor对象
if (TicketCenter.tickets <= 0){
return;
}
System.out.println(Thread.currentThread().getName() + "卖出1张票,剩余" + --TicketCenter.tickets + "张票");
}
@Override
public void run(){
while (TicketCenter.tickets > 0){
soldTicket();//在run方法中调用同步方法即可
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
代码执行结果:2号售票员卖出1张票,剩余9张票
3号售票员卖出1张票,剩余8张票
4号售票员卖出1张票,剩余7张票
1号售票员卖出1张票,剩余6张票
4号售票员卖出1张票,剩余5张票
2号售票员卖出1张票,剩余4张票
3号售票员卖出1张票,剩余3张票
1号售票员卖出1张票,剩余2张票
4号售票员卖出1张票,剩余1张票
1号售票员卖出1张票,剩余0张票
import java.util.concurrent.locks.ReentrantLock;
public class TicketCenter {
public static int tickets = 10;
public static void main(String[] args) {
//实例化4个售票员
Conductor conductor1 = new Conductor("1号售票员");
Conductor conductor2 = new Conductor("2号售票员");
Conductor conductor3 = new Conductor("3号售票员");
Conductor conductor4 = new Conductor("4号售票员");
}
}
class Conductor implements Runnable{
Thread t;
ReentrantLock lock = new ReentrantLock();//实例化一个ReentrantLock对象
public Conductor(String name){
t = new Thread(this,name);
t.start();
}
@Override
public void run(){
while (TicketCenter.tickets > 0){
lock.lock();//加锁
if (TicketCenter.tickets <= 0){
return;
}
System.out.println(Thread.currentThread().getName() + "卖出1张票,剩余" + --TicketCenter.tickets + "张票");
lock.unlock();//解锁
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
代码执行结果:1号售票员卖出1张票,剩余9张票
3号售票员卖出1张票,剩余8张票
2号售票员卖出1张票,剩余7张票
4号售票员卖出1张票,剩余6张票
1号售票员卖出1张票,剩余5张票
3号售票员卖出1张票,剩余4张票
4号售票员卖出1张票,剩余3张票
2号售票员卖出1张票,剩余2张票
1号售票员卖出1张票,剩余1张票
3号售票员卖出1张票,剩余0张票
死锁:多个线程彼此占有对方所需要的锁对象,而不释放自己的锁。
public class DeadLock {
public static void main(String[] args) {
Runnable runnable1 = () -> {
synchronized ("A"){
System.out.println("A线程持有了A锁,等待B锁");
synchronized ("B"){
System.out.println("A线程同时持有了A锁和B锁");
}
}
};
Runnable runnable2 = () -> {
synchronized ("B"){
System.out.println("B线程持有了B锁,等待A锁");
synchronized ("A"){
System.out.println("B线程同时持有了A锁和B锁");
}
}
};
Thread t1 = new Thread(runnable1);
Thread t2 = new Thread(runnable2);
t1.start();
t2.start();
}
}
代码执行结果:B线程持有了B锁,等待A锁
A线程持有了A锁,等待B锁
此时两个线程都无法访问对方手里的那个锁标记,程序进入死锁状态。 public class DeadLock {
public static void main(String[] args) {
Runnable runnable1 = () -> {
synchronized ("A"){
System.out.println("A线程持有了A锁,等待B锁");
try {
"A".wait();//将先抢走A锁的进程执行wait操作
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized ("B"){
System.out.println("A线程同时持有了A锁和B锁");
}
}
};
Runnable runnable2 = () -> {
synchronized ("B"){
System.out.println("B线程持有了B锁,等待A锁");
synchronized ("A"){
System.out.println("B线程同时持有了A锁和B锁");
"A".notifyAll();//等现持有B锁的线程先占用A锁完成任务之后将等待队列中所有被A锁约束的线程唤醒
}
}
};
Thread t1 = new Thread(runnable1);
Thread t2 = new Thread(runnable2);
t1.start();
t2.start();
}
}
代码执行结果:A线程持有了A锁,等待B锁
B线程持有了B锁,等待A锁
B线程同时持有了A锁和B锁
A线程同时持有了A锁和B锁