多线程

进程:系统可以进行独立调配并且不可分割的独立单元

线程:进程的一个独立单元

进程有多个任务,每个任务就是一个线程

多线程程序:如果一个程序有多条执行路径,则该程序为多线程程序

多线程特点:线程之间抢占CPU执行权

多线程具有随机性

 面试题:JVM是多线程程序吗?至少有几条线程..

  jvm是多线程的,

 至少有2条线程...

  有主线程,main..执行这些代码,能够被Jvm识别

 在执行一些程序的时候,一些对象Jvm释放掉,原因,

 它开启了垃圾回收线程,里面GC:垃圾回收器(回收一些没有更多引用的对象或者变量...)

并行和并发(高并发:MyBatis --->IBatis:半自动化)

  并行:逻辑上的同时,指的是同一个时间段内

  并发:物理上的同时,指的是同一个时间点

Java提供了一个类:Thread

实现多线程程序方式一的步骤:

 1)将类声明为 Thread 的子类

 2)该子类应重写 Thread 类的 run 方法

 3)在主线程进行该自定义的线程类的对象的创建

 

Thread 类提供了一些方法

  public final void setName(String name):给线程起名称

  public final String getName() :获取线程名称

public final void setDaemon(boolean on) :true,表示为守护线程

 说明: 将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。(守护线程不会立即结束掉,它会执行一段时间在结束掉)该方法必须在启动线程前调用。

跟线程优先级相关的方法:

  public final int getPriority()返回线程的优先级。

  public final void setPriority(int newPriority)更改线程的优先级

线程存在一个默认优先级

 public static final int MAX_PRIORITY 10 最大优先级

 public static final int MIN_PRIORITY 1 最小优先级

 public static final int NORM_PRIORITY 5 默认优先级

其他常用方法:

public final void join():等待该线程终止

public static void sleep(long millis):线程睡眠 指定是时间毫秒值

public final void stop() ;强迫线程停止执行。 不会执行了

public void interrupt()中断线程。 表示中断线程的一种状态

 public static void yield()暂停当前正在执行的线程对象,并执行其他线程

 

Wait()sleep()的区别:

wait(): wait()调用的,立即释放锁  (同步锁/Lock)

sleep():线程睡眠,调用不会释放锁

继承extends的方式创建多线程:

package org.westos_06;

 

public class MyThread extends Thread {

@Override

public void run() {

for(int x = 0 ; x <100 ; x ++) {

System.out.println(getName()+":"+x);

}

}

}

 

package org.westos_06;

 

public class ThreadDemo {

 

public static void main(String[] args) {

//创建三个子线程

MyThread t1 = new MyThread() ;

MyThread t2 = new MyThread() ;

MyThread t3 = new MyThread() ;

t1.start();

t2.start();

t3.start();

}

}

注意:

Run()方法封装被执行的代码,直接调用则是普通方法的调用

Start()方法启动线程,并由jvm自动调用run()方法

实现多线程程序的第二种方式:

 1)自定义一个类,实现Runnable接口

 2)实现接口中的run方法,对耗时的代码进行操作

 3)然后在主线程中创建该了对象,将该类对象做为一个资源类,创建Threadd类的对象,将刚才的资源类作为参数进行传递

 实现runnable接口的方法示例:

package org.westos_07;

 

//自定义类实现接口,实现run方法

public class MyThread implements Runnable {

 

@Override

public void run() {

for(int x= 0; x <100 ; x ++) {

//	System.out.println(getName()+":"+x);

System.out.println(Thread.currentThread().getName()+":"+x);

}

}

 

}

package org.westos_07;

 

public class ThreadDemo {

public static void main(String[] args) {

//创建当前类对象

MyThread my =new MyThread() ;

//实现多线程

//public Thread(Runnable target,String name)

Thread t1 = new Thread(my, "线程1") ;

Thread t2 = new Thread(my, "线程2") ;

//启动线程

t1.start();

t2.start();

}

}

校验一个多线程程序是否有安全问题的隐患的前提条件:

   1)当前程序是否是多线程环境

   2)是否有共享数据

   3)是否有多条语句对共享数据进行操作

解决安全问题:

   1)多线程环境 不能解决

   2)对共享数据进行优化 不能解决

   3)解决将多条语句对共享数据这一环进行解决

 解决方案:就是将多条语句对共享数据操作的代码,用一个代码包起来---->代码--->同步代码块

同步机制:

格式:

   synchronized(锁对象){

   针对多条语句对共享数据操作代码;

   }

 注意:

 锁对象:肯定一个对象,随便创建一个对象(匿名对象)

  锁对象:多个线程必须使用同一把锁

同步的优点:解决多线程的安全问题

同步的弊端:当线程很多时,每个线程都会去判断同步上的锁,消耗资源,降低了运行效率。并且如果出现了同步嵌套,就会出现死锁问题

Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构

  可以使用Lock锁进行具体的锁定操作类 提供了具体的实现类:ReentrantLock

 使用方式:

void lock()加锁

void unlock()释放锁

死锁问题:两个或两个以上的线程,在执行的过程中出现互相等待的情况

什么叫死锁问题?代码说明

package org.westos_08;

public class MyLock {

 

//两个锁对象分别是objA 和objB

public static final Object objA = new Object() ;

public static final Object objB = new Object() ;

}

 

package org.westos_08;

 

public class DieLock extends Thread {

//声明一个成语变量

private boolean flag ;

public DieLock(boolean flag) {

this.flag = flag ;

}

//重写run方法

@Override

public void run() {

if(flag) {

synchronized (MyLock.objA) {

System.out.println("if ObjA");

synchronized (MyLock.objB) {

System.out.println("if objB");

}

}

}else {

synchronized (MyLock.objB) {

System.out.println("else objB");

synchronized (MyLock.objA) {

System.out.println("else objA");

}

}

}

}

}

package org.westos_08;

 

 

public class DieLockDemo {

public static void main(String[] args) {

//创建线程了对象

DieLock dl1 = new DieLock(true) ;

DieLock dl2 = new DieLock(false) ;

//启动线程

dl1.start();

dl2.start();

}

}

解决死锁问题:

保证生产者线程和消费者线程针对同一个对象进行操作的!

  具体操作:在外部创建一个资源类,将这个资源类对象对象通过构造方法传入到各个线程中

等待唤醒机制:

通过锁对象调用的方法(object类):

Wait():等待

Notify():唤醒单个线程

Notify():唤醒所有线程

生产者—消费者问题:

A. 生产者线程抢占CPU执行权,如果本身没有数据则生产数据,如果本身有数据则等待消费者线程消费

B. 消费者线程抢占CPU执行权,如果已有数据则消费数据,如果没有数据则等待生产者生产数据

代码说明:

package org.westos_11;

 

//生产者线程

public class SetThread  implements Runnable {

private Student s ;

public SetThread(Student s) {

this.s = s ;

}

//定义一个变量

private int x = 0 ;

@Override

public void run() {

//设置学生数据

//	Student s = new Student() ;

while(true) {

synchronized (s) {

//判断有没有数据的情况

if(s.flag) {

try {

s.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

if(x%2 ==0) {

s.name = "高圆圆" ;	//高圆圆---27

s.age = 27 ;

}else {

s.name = "张杨";

//张杨

s.age = 28 ;

}

x++ ;

//如果有数据了,更改flag值

s.flag = true ;//有数据了

//通知t2线程消费数据,唤醒

s.notify();  //唤醒t2线程,唤醒之后t1,t2都互相抢占

}

}

}

}

package org.westos_11;

 

//消费者线程

public class GetThread implements  Runnable {

private Student s ;

public GetThread(Student s) {

this.s = s ;

}

@Override

public void run() {

//输出该学生数据

//	Student s = new Student() ;

while(true) {

synchronized (s) {

//如果本身消费者有数据

if(!s.flag) {

try {

s.wait();//和网络编程中TCP编程里面的accept() 都属于阻塞式方法

//消费线程等待,等待该线程先输出这些数据(立即释放锁对象)

} catch (InterruptedException e) {

e.printStackTrace();

}

}

System.out.println(s.name +"----"+s.age);//高圆圆---27

//如果没有数据类,

s.flag = false ;

//通知t1线程,赶紧产生数据

s.notify(); //唤醒单个线程

}

//张杨---27

}

}

}

 

线程组:表示一个线程的集合。此外,线程组也可以包含其他线程组

public final ThreadGroup getThreadGroup()返回该线程所属的线程组

public final String getName():返回线程组的名称

所有的线程它默认的线程组名称:main(主线程)

 

线程池:多个线程执行完毕,它会重新回到线程池中,等待被利用,不会变成垃圾!

 和线程池有关的类

  Executors: 一种工厂类

  方法:

  和线程池的创建有关系

  public static ExecutorService newFixedThreadPool(int nThreads)创建一个可重用固定线程数的线程池

 

 ExecutorService:可以执行异步任务

  创建一个线程池,执行接口中的方法

提交:Future<?> submit(Runnable task)

 * <T> Future<T> submit(Callable<T> task)提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future

 Future:接口

  Future 表示异步计算的结果

  线程池调用完毕可以关闭的

void shutdown():关闭之前,会提交刚才的任务

多线程实现方式第三种方式:

 前提:自定义类实现Callable接口

 1)创建线程池对象: Executors 里面的那个方法,返回的是ExecutorsService

 2) 然后调用ExecutorsService里面的提交任务的方法:

 <T> Future<T> submit(Callable<T> task)提交一个返回值的任务用于执行

3) 关闭线程池

代码举例:

import java.util.concurrent.Callable;

 

public class MyCallable implements Callable<Integer> {

//定义个变量

private int number ;

 

public MyCallable(int number) {

this.number = number;

}

@Override

public Integer call() throws Exception {

//定义最终结果变量

int sum = 0 ;

for(int x =1 ; x <=number ; x ++) {

sum +=x ;

}

return sum;

}

 

}

package org.westos_15;

 

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

 

/**

 *分别计算每个线程的求和!

 *

 */

public class ExecutorsTest {

public static void main(String[] args) throws InterruptedException,

ExecutionException {

//创建线程池对象

ExecutorService pool = Executors.newFixedThreadPool(2) ;

//提交任务

Future<Integer> f1 = pool.submit(new MyCallable(100)) ;

Future<Integer> f2 = pool.submit(new MyCallable(200)) ;

//V get():获取结果

Integer i1 = f1.get() ;

Integer i2 = f2.get() ;

System.out.println(i1);

System.out.println(i2);

//关闭线程池

pool.shutdown();

}

}

线程的生命周期图解:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值