廖雪峰Java11多线程编程-1线程的概念-2创建新线程
Java语言内置多线程支持:
- 一个Java程序实际上是一个JVM进程
- JVM用一个主线程来执行main()方法
- 在main()方法中又可以启动多个线程
1.创建新线程
要启动一个线程,需创建一个线程对象。创建线程对象的方法有3种。
1.1 方法一:使用Thread创建线程
创建MyThread类:
- 从Thread派生
- 覆写run()方法
- 创建MyThread()实例
- 对这个实例调用start()启动线程
class MyThread extends Thread{
public void run(){
System.out.println("子线程");
}
}
public class Main {
public static void main(String[] args){
Thread t = new MyThread();
t.start();
}
}
疯狂Java示例
package com.thread;
public class FirstThread extends Thread{
private int i;
public FirstThread(){}
public FirstThread(String name){
super(name);
}
public void run(){
for(;i<10;i++) {
System.out.println(getName()+i);
}
}
public static void main(String[] args) throws InterruptedException{
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+i);
if(i==5){
new FirstThread().start();
Thread.sleep(500);
new FirstThread("通过集成Thread创建新线程").start();
}
Thread.sleep(500);
}
}
}
1.2 方法二:使用Runnable接口创建新线程
如果一个类已经从某个类派生,无法从Thread继承:
- 实现Runnable接口
- 覆写run()接口
- 在main()方法中创建Runnable实例
- 创建Thread实例并传入Runnable
- 调用start()启动线程
class MyThread implements Runnable{
public void run(){
System.out.println("子线程");
}
}
public class Main {
public static void main(String[] args){
Runnable mt = new MyThread();
Thread t = new Thread(mt);
t.start();
}
}
疯狂Java示例
package com.thread;
public class SecondThread implements Runnable{
private int i;
public void run(){
for(;i<10;i++){
System.out.println(Thread.currentThread().getName()+"的循环变量"+i);
}
}
public static void main(String[] args) throws InterruptedException{
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"的循环变量"+i);
if(i==5){
SecondThread st = new SecondThread();
new Thread(st,"新线程1").start();
Thread.sleep(500);
new Thread(st,"新线程2").start();
Thread.sleep(500);
}
Thread.sleep(500);
}
}
}
1.3 方法三:使用Futrue和Callable创建子线程
实现Callable接口,覆写call()方法。再用Future进行转换
class WithResult implements Callable<Integer>{
@Override
public Integer call() throws Exception {
return 5;
}
}
public class ForZhang {
public static void main(String[] args) throws Exception{
Callable<Integer> th = new WithResult();
FutureTask task = new FutureTask<>(th);
new Thread(task,"有返回值的线程").start();
}
}
示例
package com.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThirdThread{
public static void main(String[] args) throws InterruptedException{
ThirdThread th = new ThirdThread();
FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)()->{
int i=0;
for(;i<10;i++){
System.out.println(Thread.currentThread().getName()+"的循环变量的值"+i);
}
return i;
});
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"循环变量的值"+i);
if(i==5){
new Thread(task,"有返回值的线程").start();
}
Thread.sleep(500);
}
try{
System.out.println("线程task的返回值:"+task.get());
}catch (ExecutionException e){
e.printStackTrace();
}
}
}
同
class WithResult implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int i=0;
for(;i<10;i++){
System.out.println(Thread.currentThread().getName()+"的循环变量的值"+i);
}
return i;
}
}
public class ThirdThread {
public static void main(String[] args) throws Exception{
Callable<Integer> th = new WithResult();
FutureTask task = new FutureTask<>(th);
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"循环变量的值"+i);
if(i==5){
new Thread(task,"有返回值的线程").start();
}
Thread.sleep(500);
}
try{
System.out.println("线程task的返回值:"+task.get());
}catch (ExecutionException e){
e.printStackTrace();
}
}
}
2.启动线程需要注意的地方
2.1 直接调用run()方法
直接调用run()方法是无效的,相当调用普通的Java的方法,当前线程没有任何的改变,也不会启动新的线程。
class MyThread extends Thread{
public void run(){
System.out.println("当前线程"+Thread.currentThread().getName()+"\tHello");
}
}
public class Main {
public static void main(String[] args){
Thread t = new MyThread();
t.run();//直接调用run()方法
Thread t2 = new MyThread();
t2.start();
System.out.println("主线程"+Thread.currentThread().getName());
}
}
start源码
class Thread implements Runnable {
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0(); //调用JVM虚拟机内部的start0()方法
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {}
}
}
private native void start0(); //native表示JVM虚拟机内部的C代码实现的,不是由Java代码实现的
2.2 新线程和主线程是同时执行
默认情况下,新线程和主线程是同时执行的,由操作系统调度,程序本身无法确认线程的的调度顺序
class HelloThread extends Thread{
String name;
public HelloThread(String name){
this.name = name;
}
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("Hello, " + name + "!");
try{
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args){
Thread t1 = new HelloThread("Bob");
t1.start();
Thread t2 = new HelloThread("Alice");
t2.start();
for(int i=0;i<3;i++){
System.out.println("Main!");
try{
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
3 线程的优先级
- 可以对线程设定优先级 Thread.setPriority(int n)//1-10,默认值5
- getPriority()获取线程的优先级
- 每个线程默认的优先级都与创建它的父线程的优先级相同,默认情况下,main线程具有普通优先级,其子线程也具有普通优先级。
- 优先级高的线程被操作系统调度的优先级高
- 不能通过设置优先级来确保功能的执行顺序
public class PriorityTest extends Thread{
public PriorityTest(String name){
super(name);
}
public void run(){
for(int i=0;i<50;i++){
System.out.println(getName()+",其优先级是:"+getPriority()+"的循环变量的值为:"+i);
}
}
public static void main(String[] args){
Thread.currentThread().setPriority(6);
for(int i=0;i<30;i++){
if(i==10){
PriorityTest low = new PriorityTest("低级");
low.start();
System.out.println("创建之初的优先级:"+low.getPriority());
low.setPriority(Thread.MIN_PRIORITY);
}
if(i==20){
PriorityTest high = new PriorityTest("高级");
high.start();
System.out.println("创建之初的优先级:"+high.getPriority());
high.setPriority(Thread.MAX_PRIORITY);
}
}
}
}
高优先级的线程将会获得更多的执行机会,因此尽管高优先级的执行晚,却早结束。
虽然Java提供了10个优先级,但不同操作系统的优先级并不相同,而且也不能很好的和Java的10个优先级对应,因此尽量使用MAX_PRIORITY, MIN_PRIORITY, NORM_PRIORITY
4总结:
- Java用Thread对象表示一个线程,通过调用start()启动一个线程
- 一个线程对象只能调用一次start()
- 线程的执行代码是run()方法
- 线程调度由操作系统决定,程序本身无法决定
- Thread.sleep()可以把当前线程暂停一段时间