【五】Java基础(04)---多线程

目录

一.基础概念

二.多线程创建方式

线程创建方式一:Thread

线程创建方式二:Runnable

线程创建方式三:Callable

线程创建方式四:线程池


一.基础概念

程序: 是为完成特定的任务,用某种语言编写的一组指令的集合,即指一段静态的代码,静态对象

进程: 是程序的一次执行过程,运行中的程序。是一个动态的过程,有它自身的产生,存在,消亡的过程 ----生命周期

程序是静态的,进程是动态的

进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域

线程: 进程可进一步细化为线程,是一个程序内部的一条执行路径

若一个i进程同一时间并行执行多个线程,就是支持多线程的

线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销小

一个进程中的多个线程共享相同的内存单位/内存地址空间->他们从同一堆中分配的对象,可以访问相同的变量和对象。这就使得线程间通信更简便,高效。但多个线程操作共享的系统资源可能就会带来安全的隐患

单核cpu 和多核cpu

单核cpu:实际上是假的多线程,因为在一个时间单元内,也只能执行一个线程的任务

多核CPU: 才能更好的发挥多线程的效率

(Java应用程序Java.exe ,其实至少有三个线程:main()主线程,gc()垃圾回收线程,异常处理线程,当然如果发生异常,会影响主线程。)

并行 :多个cpu同时执行多个任务。

并发:一个CPU同时执行多个任务。比如:秒杀,多个人做同一件事。

二.多线程创建方式

线程创建方式一:Thread

Thread类

1.创建一个继承于Thread类的子类

2.重写Thread类的run()  -->将此线程执行的操作声明在run()

3.创建Thread类的子类的对象

4.通过此对象调用start()

(启动当前线程,调用当前线程的run()

5.创建匿名子类

new Thread(){

@override

Public void run(){

}

}.start();

测试Thread的常用方法

1.start():启动当前线程;调用当前线程的方法run();

2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中

3.currentThread():静态方法,返回当前执行代码的线程

4.getname():获取当前线程的名字

5.setname():设置当前线程的名字

6.yield():释放当前CPU执行权给高优先级线程

7.join():在线程a中调用线程b中的join(),此时线程a进入阻塞状态,直到线程完全执行完以后,线程a才结束阻塞状态

8.stop():已过时。当执行此方法,结束线程

9.sleep():静态方法,让当前线程睡眠指定时间毫秒。在指定的毫秒时间内,当前线程阻塞状态

10.isAlive():判断当前线程是否存活

  线程的调度:

线程的优先级:

1.

MAX_PRIORITY: 10

MIN_PRIORITY: 1

NORM_PRIORITY: 5 -->默认优先级

2.如何获取和设置当前线程的优先级:

getPriority(): 获取当前线程的优先级

setPriority(int p):设置当前线程的优先级

说明:高优先级线程要抢占低优先级线程CPU的执行全,但是只是从概率上讲,不意味着有顺序  

packagecom.example.thread;


class MyThread extends Thread{
@Override
public void run(){
for(int i=0;i<100;i++){
if(i%2==0){
System.out.println(i);
}
}
}
}
public class Thread Test{
public static void main(String[] args){

MyThread mathread=new MyThread();
mathread.start();
for(inti=0;i<100;i++)
System.out.println("hello");
}
}

案例,三个窗口卖票

//thread方式创建线程
packagecom.example.sailtext;
//存在线程安全,创建三个窗口卖票
public class WindowTest{
public static void main(String[] args){
Windowt1=new Window();
Windowt2=new Window();
Windowt3=new Window();

t1.setName("window-1");
t2.setName("window-2");
t3.setName("window-3");

t1.start();
t2.start();
t3.start();
}
}

class Window extends Thread{

private static int ticket=100;
@Override
public void run(){
while(true){

if(ticket>0){
System.out.println(getName()+":卖票,票号为:"+ticket);
ticket--;
}
else{
break;
}
}
}
}

线程创建方式二:Runnable

 实现Runnable接口

1.创建一个实现Runnable接口的类

2.实现类去实现Runnable中的抽象方法 run();

3.创建实现类的对象

4.将此对象作为参数传递到Thread类中的构造器中,创建Thread类的对象

5.通过Thread类的对象调用 start();

package com.example.runnabletext;

class MThread implements Runnable{

@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){
MThreadm1=new MThread();//MThread implements Runnable
Threadt1=new Thread(m1);//Thread(Runnabletarget)
t1.start();//此时调用的方法是根据thread里判断实现接口中的run方法
Threadt2=new Thread(m1);
t2.start();
}
}

案例,三个窗口卖票

package com.example.WindowTest1;
/*
三个窗口卖票
*/

public class WindowTest{

public static void main(String[]args){

Windowsw1=new Windows();
Threadt1=new Thread(w1);
Threadt2=new Thread(w1);
Threadt3=newT hread(w1);

t1.setName("window-1");
t2.setName("window-2");
t3.setName("window-3");

t1.start();
t2.start();
t3.start();


}

}

class Windows implements Runnable{

private int ticket=100;

@Override
public void run(){

while(true){

if(ticket>0){
System.out.println(Thread.currentThread().getName()+":"+ticket);
}
else{
break;
}
ticket--;
}
}
}

线程创建方式三:Callable

Callable 比Runnable的强大之处

call方法可以有返回值

call方法可以抛出异常,被外面的操作捕获

Callable支持泛型

package com.example.callable;


import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;


//1.创建一个实现Callable接口的实现类
class NumThread implements Callable{
//2.实现call方法
@Override
public Object call() throws Exception{
int sum=0;
for(int i=1;i<100;i++){
if(i%2==0){
System.out.println(i);
sum+=i;
}
}
return sum;//自动装箱成Interger
}
}

public class ThreadNew{
public static void main(String[]args){

//3.创建Callable接口实现的对象
NumThread numThread=new NumThread();
//4.将此Callable接口实现类对象作为传递到FutureTask构造器中,创建FutureTask对象
FutureTask futureTask=new FutureTask(numThread);
//5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()方法
Threadt1=newThread(futureTask);
t1.start();

try{

//6.获取callable中call的返回值
Objectsum=futureTask.get();//只是为了获取返回值
System.out.println(sum);


}catch(InterruptedExceptione){
e.printStackTrace();
}catch(ExecutionExceptione){
e.printStackTrace();
}
}
}

线程创建方式四:线程池

待完善

线程生命周期

 线程同步

1.问题: 卖票过程中出现重票和错票---->线程安全问题

2.原因:当某个线程,操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票

3.解决:当一个线程在操作ticket中其他线程不能参与进来,直到线程a,操作完ticket 其他线程才开始操作ticket,这种情况即使线程出现阻塞,也不能改变

4.在Java中通过同步机制来解决线程安全的问题

方式一:同步代码块(synchornized)

synchronized(同步监视器){

需要被同步的代码(操作共享数据的代码,即为需要被同步的代码,共享数据:多个线程共同操作的变量。比如 :ticket ) 必须包含准确

}

同步监视器 俗称 锁。任何一个类的对象,都可以充当锁

                要求:多个线程必须要共用同一把锁

补充: 继承Thread类多线程方式中,一般不可以用this 充当锁,可以考虑当前类

           继承Runnable接口多线程方式中,一般使用this充当锁

packagecom.example.WindowTest1;
/*
三个窗口卖票 同步代码块解决runnable接口
*/

public class WindowTest{

public static void main(String[] args){

Windowsw1=new Windows();
Threadt1=new Thread(w1);
Threadt2=new Thread(w1);
Threadt3=new Thread(w1);

t1.setName("window-1");
t2.setName("window-2");
t3.setName("window-3");

t1.start();
t2.start();
t3.start();
}
}

class Windows implements Runnable{

private int ticket=100;
Object obj=new Object();
@Override
public void run(){

while(true){
synchronized(obj){    //或者this 表示当前对象
if(ticket>0){
System.out.println(Thread.currentThread().getName()+":"+ticket);
}else{
break;
}
ticket--;
}
}
}
}

 

package com.example.sailtext;

//存在线程安全,创建三个窗口卖票   同步代码块解决继承Thread 的多线程问题

public classWindowTest{ 

public static void main(String[]args){

Windowt1=new Window();

Windowt2=new Window();

Windowt3=new Window();

t1.setName("window-1");

t2.setName("window-2");

t3.setName("window-3");

t1.start();

t2.start();

t3.start();

}

}

class Window extends Thread{

private static int ticket=100;

Private static Object obj = new Object();

@Override

public void run(){

synchronized(obj){    //Window.class来代替

while(true){

if(ticket>0){

System.out.println(getName()+":卖票,票号为:"+ticket);

ticket--;

}

}

else{

break;

}

}

}

}

方式二:同步方法

1.runnable 接口多线程同步问题

将需要同步的代码块 包装成方法 比如show();

Private synchronized void show(){

//}

//锁是默认锁当前对象

2.Thread类继承多线程同步问题

Private  static synchronized void show(){

//}

//锁是当前的类

方式三:Lock锁

private ReentrantLock lock = new ReentrantLock();

lock.lock();

lock.unlock();

面试题 synchronized Lock的异同

不同点:synchronized 机制在执行完相应的代码块后,自动的释放同步监视器

             Lock手动启动 同步和手动结束同步

死锁的理解:

1.不同的线程分别占用分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁

2.出现死锁的现象是所有线程出现阻塞  

Sleep 与wait 的异同:

相同点:一旦执行,都可以使得当前线程进入阻塞状态

不同点:1.两个方法声明位置不同 Thread类中声明sleep ;Object 类中声明 wait

               2.sleep可以在任何需要的场景,wait方法必须使用在同步代码块和方法中

               3.若都用在同步代码块和方法中sleep方法不会释放锁,wait会释放锁。

wait()方法,一旦执行此方法,当前线程进入阻塞状态,并释放同步监视器

notify() 方法,就会唤醒wait的一个现线程,若是多个就唤醒优先级高的

notify all()方法,就会唤醒所有被wait的线程

注意点

涉及到线程通信,此三个方法只能出现在同步代码块,或同步方法中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值