Java知识点——多线程基础

多线程

通过继承Thread类实现多线程

Thread类存放在java.lang类库中,无需显示加载

Thread类中,已经定义了run()方法,如果想要实现多线程,必须定义自己的子类,继承与Thread类,同时要重写Thread类的run方法,然后用用户自定义的线程类,生成对象,并调用该对象的start()方法,从而来激活一个线程。

public class ThreadDemo_1 {
	public static void main(String[] args) {
		new TestThread().start();
		
		for(int i = 0; i < 5; i++) {
			System.out.println("main 线程运行");
			try {
				Thread.sleep(1000);
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

class TestThread extends Thread{
	public void run() {
		for(int i = 0; i < 5; i++) {
			System.out.println("Thread 线程运行");
			try {
				Thread.sleep(1000);
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

通过实现Runnable接口实现多线程

public class RunnableThread {
	public static void main(String[] args) {
		TestThread2 newTh = new TestThread2();
		new Thread(newTh).start();  // 使用Thread类的start方法启动线程
		for(int i = 0; i < 5; i++) {
			System.out.println("main 线程运行");
			try {
				Thread.sleep(1000);
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
		
	}
}

class TestThread2 implements Runnable{
	public void run() {
		for(int i = 0; i < 5; i++) {
			System.out.println("TestThread2 线程运行");
			try {
				Thread.sleep(1000);
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

Thread和Runnable两种多线程机制的比较

  • Thread类实现了Runnable接口,本质上,Thread类是Runnable接口众多的实现子类中的一个
  • 接口是功能的集合,只要实现了Runnable接口,就具备了可执行的功能
public class ThreadDemo {
	public static void main(String[] args) {
		TestThread3 newTh = new TestThread3();
		newTh.start();
		newTh.start();
		newTh.start();
		newTh.start();
	}
}

class TestThread3 extends Thread{
	private int tickets = 5;
	public void run() {
		while(tickets > 0) {
			System.out.println(Thread.currentThread().getName() + "出售票" + tickets);
			tickets -= 1;
		}
	}
}

结果为:

Thread-0出售票5
Thread-0出售票4
Thread-0出售票3
Thread-0出售票2
Thread-0出售票1
Exception in thread "main" java.lang.IllegalThreadStateException
	at java.lang.Thread.start(Unknown Source)
	at ThreadDemo.ThreadDemo.main(ThreadDemo.java:7)

从运行结果来看,程序出现了异常,只有却只有一个线程在运行,这说明一个类继承了Thread类之后,这个类的实例化对象,无论调用多少次start()方法,结果都只有一个线程在运行

接下来我们来实现四个线程

public class ThreadDemo {
	public static void main(String[] args) {
//		TestThread3 newTh = new TestThread3();
//		newTh.start();
//		newTh.start();
//		newTh.start();
//		newTh.start();
		new TestThread3().start();
		new TestThread3().start();
		new TestThread3().start();
		new TestThread3().start();
		
	}
}

class TestThread3 extends Thread{
	private int tickets = 5;
	public void run() {
		while(tickets > 0) {
			System.out.println(Thread.currentThread().getName() + "出售票" + tickets);
			tickets -= 1;
		}
	}
}

结果为:

Thread-0出售票5
Thread-3出售票5
Thread-3出售票4
Thread-2出售票5
Thread-1出售票5
Thread-1出售票4
Thread-1出售票3
Thread-2出售票4
Thread-3出售票3
Thread-0出售票4
Thread-3出售票2
Thread-2出售票3
Thread-1出售票2
Thread-2出售票2
Thread-3出售票1
Thread-0出售票3
Thread-2出售票1
Thread-1出售票1
Thread-0出售票2
Thread-0出售票1

从结果看出,程序总共有4个线程,但是每个线程占有自己的资源,都有5张票,如果想要达到资源共享的目的,可以使私有变量tickets变成静态变量

下面来看一下Runnable接口的实现

public class RunnableDemo {
	public static void main(String[] args) {
		TestThread4 newTh = new TestThread4();
		new Thread(newTh).start();
		new Thread(newTh).start();
		new Thread(newTh).start();
		new Thread(newTh).start();
	}
}

class TestThread4 implements Runnable{
	private static int tickets = 5;
	public void run() {
		while(tickets > 0) {
			System.out.println(Thread.currentThread().getName() + "出售票" + tickets);
			tickets -= 1;
		}
	}
}

从结果看,Runnable达到了资源共享的目的

可见,实现Runnable接口相对于继承Thread类来说,有如下的优势:

  • 避免了由于Java的单继承特性带来的局限性
  • 可使多个线程共享相同的资源,以达到资源共享的目的

Java8中运行线程的新方法

Lamda表达式:

Thread thread = new Thread(()->{System.out.println("Java 8");}).start();

()->{System.out.println("Java 8");}就是Lamda表达式

Lamda表达式的机构可大体分为3个部分:

  • 最前面的部分是一对括号,里面是参数,这里无参数,就是一对空括号
  • 中间是->,用来分割参数和主体
  • 主体部分可以是一个表达式或者一个语句块,用花括号括起来,如果一个表达式,表达式的值会作为返回值放回。如果是语句块,需要用return语句指定返回值。
public class LamdaDemo {
	public static void main(String[] args) {
		Runnable task = ()->{
			String threadName = Thread.currentThread().getName();
			System.out.println("Hello " + threadName);
		};
		
		task.run();
		Thread thread = new Thread(task);
		thread.start();
		
		System.out.println("Done!");
	}
}

线程基本操作

  • 获取线程名称
Thread t = Thread.currentThread();
t.getName();
  • 设置线程名字
public  class GetSetNameThreadDemo implements Runnable{
	public void run(){
		Thread temp = Thread.currentThread();
		System.out.print(temp.getName());
	}
	public static void main(String[] args{
		Thread t = new Thread(new GetSetNameThreadDemo());
		t.setName("thread_test1");
		t.start();
	}
}
  • 判断线程是否启动
Thread t = Thread.currentThread();
t.isAlive();
t.start();
t.isAlive();

守护线程与setDaemon方法

在JVM中,线程分为两类:用户进程和守护进程。

Thread源码中:

private boolean daemon = false;

这意味着,默认创建的线都是普通的用户线程,只有调用setDeamon(true)之后,才能转成守护进程

线程的特点

  • 同步代码块和同步方法锁的是对象,而不是代码,即如果某个对象被同步代码块或者同步方法锁住,那么其他使用该对象的代码必须等待,直到该对象的锁被释放。
  • 如果有个进程只有后台线程,则这个进程就会结束
  • 每一个已经被创建的线程在结束之前均会处于就绪、运行、阻塞状态之一
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值