Java多线程

目录

1.进程

2.线程

2.1.多线程

继承Thread类

实现Runnable接口

实现Callable接口

2.2.线程的状态

2.3.线程的调度

2.4.多线程共享数据

同步方法

同步代码块

总结


1.进程

  • 应用进程的执行实例。
  • 有独立的内存空间和系统资源

2.线程

  • CPU调度和分派的基本单元
  • 执行运算的最小单位,可完成一个独立的顺序控制流程

2.1.多线程

  • 如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为“多线程”。
  • 多个线程交替占用CPU资源,而非真正的并行执行。

优点:

  • 充分利用CPU的资源
  • 简化编程模型
  • 带来良好的用户体验

线程的创建和启动

  • 继承java.lang.Thread
  • 实现java.lang.Runnable接口
  • 实现Callable接口

实现线程的步骤:

  1. 定义线程
  2. 创建线程对象
  3. 启动线程
  4. 终止线程

继承Thread类

  • 定义xx类继承Thread类
  • 重写run()方法,编写线程执行体
  • 创建线程对象,调用start()方法启动线程

public class MyThread extends Thread{
     public void run() {
        for (int i = 1; i <= 20; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        } 
     }
}

public class TestThread {

    public static void main(String[] args) {
        //创建线程对象
        MyThread myThread = new MyThread();
        MyThread myThread1 = new MyThread();
        //启动线程
        myThread.start();
        myThread1.start();
     }

}

  •  多个线程交替执行,不是真正的”并行“
  • 线程每次执行时长由分配的CPU时间片长度决定

------------------------------------------------------------------------------------

调用run()方法和start()方法执行线程的区别:

        当主线程main中调用run()方法来启动线程的时候,会依次调用run()方法,会失去线程的意义,run()方法会被当做main()方法中的一个普通方法来执行。

------------------------------------------------------------------------------------

实现Runnable接口

  • 定义MyRunnable类实现Runnable接口
  • 实现run()方法,编写线程执行体
  • 创建线程对象,调用start()方法启动线程

public class MyThread2 implements Runnable{
     public void run() {
        for (int i = 1; i <= 20 ; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        } 
     }
}

public class TestThread2 {

    public static void main(String[] args) {
        //创建线程对象
        Runnable runnable = new MyThread2();
        //Thread thread = new Thread(runnable);
        Thread thread = new Thread(runnable,"myThread1");
        Thread thread2 = new Thread(runnable,"myThread2");
        thread.start();
        thread2.start();
     }

}
 

------------------------------------------------------------------------------------

实现Callable接口

  • 定义XXXX类实现Callable接口
  • 重写 Object call() 方法
  • 创建线程对象,使用 FutureTask 类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。(FutureTask是一个包装器,它通过接受Callable来创建,它同时实现了 Future 和 Runnable 接口。)
  • 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
  • 调用 FutureTask 对象的 get()方法来获得子线程执行结束后的返回值

public class MyThread5 implements Callable{

    @Override
    public Object call() throws Exception {
        for (int i = 1; i <= 20 ; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
        return null;
    }  
}

public class TestThread5 {

    public static void main(String[] args) {
        //创建线程对象
        MyThread5 myThread5 = new MyThread5();
        FutureTask fTask= new FutureTask(myThread5);
        Thread thread = new Thread(fTask);
        thread.start();
     }

}


2.2.线程的状态

创建状态:新建了一个线程对象,该对象就处于新建状态( new 的时候)。

就绪状态:调用 start() 时。

阻塞状态:阻塞状态时线程因为某种原因放弃CPU使用权,暂时停止运行,直到线程进入就绪状态,才有机会转为运行状态。

运行状态:执行 run() 方法时。

死亡状态:线程执行结束或退出run()方法。


2.3.线程的调度

        线程调度指按照特定机制为多个线程分配CPU的使

      

 说       明

void setPriority(int  newPriority)

更改线程的优先级

static void sleep(long millis)

在指定的毫秒数内让当前正在执行的线程休眠

void join()

等待该线程终止

static void yield()

暂停当前正在执行的线程对象,并执行其他线程(礼让)

void interrupt()

中断线程

boolean isAlive()

测试线程是否处于活动状态

wait()

暂停一个线程

notify()

唤起一个线程

------------------------------------------------------------------------------------

线程的优先级:

  • 线程优先级由1~10表示,1最低,默认优先级为5
  • 优先级高的线程获得CPU资源的概率较大

------------------------------------------------------------------------------------

sleep

设置sleep的值可简单实现交替执行,但并不完全准确

创建两个子线程,每个线程均输出20次消息数字、“你好”、线程名!

public class MyThread extends Thread{
	 public void run() {
        for (int i = 1; i <= 20 ; i++) {
        	try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				
				e.printStackTrace();
			}
			System.out.println(i+"."+"你好,来自线程"+Thread.currentThread().getName());
		} 
     }
}
public class TestThread {

	public static void main(String[] args) {
		// 创建线程对象
		MyThread myThread = new MyThread();
		MyThread myThread1 = new MyThread();
		// 启动线程
		myThread.setName("A");
		myThread.start();
		myThread1.setName("b");
		myThread1.start();

	}

}

------------------------------------------------------------------------------------

join:

线程的强制运行:

  • 强制执行当前线程,join写在哪个线程,就阻塞谁

public final void join()

public final void join(long mills)

public final void join(long mills,int nanos)

package dh07.demo02;
//join
public class TestMyThread {

	public static void main(String[] args) {
		// 创建子线程对象
		Runnable runnable = new MyThread();
		Thread thread = new Thread(runnable, "myThread");
		thread.start();
		// 主线程main做的事情
		for (int i = 1; i <= 20; i++) {
			System.out.println(Thread.currentThread().getName() + ":" + i);
			
			//当i=5时,强制把thread线程加入执行
			if (i == 5) {
				try {
					thread.join();
				} catch (InterruptedException e) {
		
					e.printStackTrace();
				}
			}
		}

	}
}

------------------------------------------------------------------------------------

yield:

  • 暂停当前线程,允许其他具有相同优先级的线程获得运行机会。
  • 该线程处于就绪状态,不会进入阻塞状态。
  • 只是提供一种可能,但是不能保证一定会实现礼让。
public class MyThread2 implements Runnable{
	 public void run() {
        for (int i = 1; i <= 10 ; i++) {
        	String tname = Thread.currentThread().getName();
			System.out.println(tname+"线程=="+i);
			if (i==3) {
				System.out.print(tname+"线程礼让:");
				Thread.yield();
			}
			
        } 
     }
}
// yield
public class TestMyThread2 {

	public static void main(String[] args) {
		// 创建子线程对象
		Runnable runnable = new MyThread2();
		Thread thread1 = new Thread(runnable, "A");
		Thread thread2 = new Thread(runnable, "B");
		thread1.start();
		thread2.yield();
		thread2.start();

	}
}

 


 

2.4.多线程共享数据

        多个线程操作同一共享数据时,将引发数据不安全问题。

引发的原因:多线程共同操作数据时,引发的冲突(如延迟时,操作未全部完成等等)

同步方法

使用synchronized 为当前线程声明一把锁。

  • 使用 synchronized 修饰的方法控制对类成员变量的访问
    • ​​​访问修饰符 synchronized 返回类型 方法名(参数列表){……}

    • synchronized 访问修饰符 返回类型 方法名(参数列表){……}

同步代码块:

  • 使用 synchronized 关键字修饰的代码块

    • synchronized syncObject){ //需要同步的代码 }

      • 如果 syncObject 为需同步的对象,通常为 this

      • 效果与同步方法相同

同步代码块

  • 多个并发线程访问同一资源的同步代码块时
    • 一时刻只能有一个线程进入synchronizedthis)同步代码块
    • 当一个线程访问一个synchronizedthis)同步代码块时,其他 synchronizedthis)同步代码块同样被锁定
    • 当一个线程访问一个synchronizedthis)同步代码块时,其他线程可以访问该资源的非synchronizedthis)同步代码

------------------------------------------------------------------------------------

线程同步:即各线程之间要有个先来后到,不能一窝蜂。

线程同步其实是“排队”:上锁,排队,一个一个来,不能同时操作

线程安全的类型:

  • ArrayList类的add()方法为非同步方法。
  • 当多个线程向同一个ArrayList对象添加数据时,可能出现数据不一致问题。
方法是否同步效率比较适合场景
线程安全多线程并发共享资源
非线程安全单线程

常见类型对比:

  •  Hashtable  &&  HashMap 
    • Hashtable 
      • 继承关系
        • 实现了Map接口,Hashtable 继承 Dictionary 
      • 线程安全,效率较低
      • 键和值都不允许为null
    • HashMap
      • 继承关系
        • 实现了Map接口,继承 AbstractMap 
      • 非线程安全,效率较高
      • 键和值都允许为null


总结

        练习:习题跳转

posted @   愚人钊啊  阅读(10)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示