java高级阶段部分开始
多线程
一、多线程的创建
首先来体会一下多线程,体会一下切片
/**多线程的创建,方式一:继承于Thread类
* 1.创建一个继承于Thread类的子类
* 2.重写Thread类的run()--->将此线程执行的操作声明在run()中
* 3.创建Thread类的子类的对象
* 4.通过此对象调用start()
*
* 例子:遍历100以内的所有的偶数
* @author 123
* @create 2022-03-23 8:37
*/
//1.创建一个继承于Thread类的子类
class MyThread extends Thread{
//2.重写Thread类的run()
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%2==0){
System.out.println(i);
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
//3.创建Thread类的子类的对象
MyThread t1 = new MyThread();
//4.通过此对象调用start()
t1.start();
for (int i = 0; i < 100; i++) {
if (i%2!=0){
System.out.println(i+"********main*********");
}
}
}
}
通过输出结果你会发现这是交替进行的,根据每个人机器cpu的不同结果打印会不一样
如果不调用start方法而是直接调用run方法会怎么样呢?那样就只是开了一个线程,所有的都在main线程中执行了。如下图所示,就只是重写了一个方法再调用该方法,执行完该方法后又接着执行后面的代码。
/**多线程的创建,方式一:继承于Thread类
* 1.创建一个继承于Thread类的子类
* 2.重写Thread类的run()--->将此线程执行的操作声明在run()中
* 3.创建Thread类的子类的对象
* 4.通过此对象调用start()
*
* 例子:遍历100以内的所有的偶数
* @author 123
* @create 2022-03-23 8:37
*/
//1.创建一个继承于Thread类的子类
class MyThread extends Thread{
//2.重写Thread类的run()
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%2==0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
//3.创建Thread类的子类的对象
MyThread t1 = new MyThread();
//4.通过此对象调用start() ①启动当前线程 ②调用当前线程的run()
// t1.start();//start方法自动去调用上面那个被重写的run方法了,所以start方法的作用到底是什么呢?
t1.run();
//如下操作仍然是在main线程中执行的
for (int i = 0; i < 100; i++) {
if (i%2!=0){
System.out.println(Thread.currentThread().getName()+":"+i+"********main*********");
}
}
}
}
所以必须通过调用start方法去启动线程,这样结果明显能看出来是有两个线程存在
那么我用t1去两次调用start来开启两个线程可以吗?答案是不可以的
public class ThreadTest {
public static void main(String[] args) {
//3.创建Thread类的子类的对象
MyThread t1 = new MyThread();
//4.通过此对象调用start() ①启动当前线程 ②调用当前线程的run()
t1.start();//start方法自动去调用上面那个被重写的run方法了,所以start方法的作用到底是什么呢?
//问题一:我们不能通过直接调用run()的方式启动线程
//t1.run();
//问题二:再启动一个线程,遍历100以内的偶数。不可以还让start()的线程去执行。会报IllegalThreadStateException
// t1.start();
//我们需要重新创建一个线程的对象
MyThread t2 = new MyThread();
t2.start();
//如下操作仍然是在main线程中执行的
for (int i = 0; i < 100; i++) {
if (i%2!=0){
System.out.println(Thread.currentThread().getName()+":"+i+"********main*********");
}
}
}
}
总结:要想造多个线程只能通过造多个线程对象,要想启动这些线程,只能通过这些线程对象去调用start( )方法。
上述创建多线程的方法分为四个步骤,咱们可以通过创建Thread类的匿名子类方式来将这几步简化融合一下,实现不同线程执行不同的事情,如下图所示:
public class ThreadDemo {
public static void main(String[] args) {
//创建Thread类的匿名子类的方式
new Thread(){
@Override
public void run() { //偶数
for (int i = 0; i < 100; i++) {
if (i%2==0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}.start();
new Thread(){
@Override
public void run() { //奇数
for (int i = 0; i < 100; i++) {
if (i%2!=0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}.start();
}
}
二、Thread类中的常用方法
我们可以通过setName函数给线程命名,也可以通过构造器的方式给线程命名。
/**
* 测试Thread中的常用方法
* 1.start():启动当前进程:调用当前线程的run()
* 2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
* 3.currentThread():静态方法,返回执行当前代码的线程
* 4.getName():获取当前线程的名字
* 5.setName():设置当前线程的名字
* @author 123
* @create 2022-03-23 10:12
*/
class HelloThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%2==0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public HelloThread(String name){
super(name);
}
}
public class ThreadMethod {
public static void main(String[] args) {
HelloThread h1 = new HelloThread("Thread:1");
//h1.setName("线程一");
h1.start();
Thread.currentThread().setName("主线程");
for (int i = 0; i < 100; i++) {
if (i % 2 != 0) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
class HelloThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%2==0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
if (i%20==0){
this.yield();//表示想该线程想释放执行权,释放后可能(是可能不是一定)会被其他线程掌握执行权然后操作其他线程
}
}
}
public HelloThread(String name){
super(name);
}
}
public class ThreadMethod {
public static void main(String[] args) {
HelloThread h1 = new HelloThread("Thread:1");
//h1.setName("线程一");
h1.start();
Thread.currentThread().setName("主线程");
for (int i = 0; i < 100; i++) {
if (i % 2 != 0) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
如上图所示,20满足那个if条件,所以执行yield函数,释放执行权了,然后接着就被主线程抢去了
又补充了关于sleep和isAlive的用法,如下所示:
/**
* 测试Thread中的常用方法
* 1.start():启动当前进程:调用当前线程的run()
* 2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
* 3.currentThread():静态方法,返回执行当前代码的线程
* 4.getName():获取当前线程的名字
* 5.setName():设置当前线程的名字
* 6.yield():释放当前cpu的执行权
* 7.join():在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态、
* 8.stop():已经过时,当执行此方法时,强制结束当前进程
* 9.sleep(long millitime):让当前线程“睡眠”指定的millitime毫秒。在指定的millitime毫秒时间内,当前线程是阻塞状态
* 10.isAlive():判断当前线程是否存活
* @author 123
* @create 2022-03-23 10:12
*/
class HelloThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%2==0){
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
if (i%20==0){
this.yield();//表示想该线程想释放执行权,释放后可能(是可能不是一定)会被其他线程掌握执行权然后操作其他线程
}
}
}
public HelloThread(String name){
super(name);
}
}
public class ThreadMethod {
public static void main(String[] args) {
HelloThread h1 = new HelloThread("Thread:1");
//h1.setName("线程一");
h1.start();
Thread.currentThread().setName("主线程");
for (int i = 0; i < 100; i++) {
if (i % 2 != 0) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
if(i==20){
try {
h1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println(h1.isAlive());
}
}