java多线程,线程的创建,生命周期,同步,通信,线程池

线程的创建

1)继承Thread类
2)实现Runnable接口

话不多说,上代码
第一种情况

class FirstThead extends Thread{
	
	@Override
	public void run() {
		System.out.println("first thread");
	}
}

第二种情况

class SecondThread implements Runnable{

	@Override
	public void run() {
		System.out.println("second thread");
	}
	
}

public class CreateThread extends Thread{
	
	public static void main(String[] args) {
		FirstThead t1 = new FirstThead();
		t1.start();
		Thread t2 = new Thread(new SecondThread());
		t2.start();
	}

}

简单总结一下:
一个是继承Thread,一个是实现接口Runnable
继承Thread类,因为Thread里面有run’和start方法,所以不需要再经过处理
实现Runnable,因为Runnable接口里面没有run和start方法,所以需要再经过Thread包装一下。

建议使用Runnable,因为这符合面向接口编程,而且也解决了java单继承的问题

线程的生命周期

示意图:
在这里插入图片描述
在这里插入图片描述

同步

同步机制中的锁

在《Thinking in Java》中,是这么说的:对于并发工作,你需要某种方式来防止两个任务访问相同的资源(其实就是共享资源竞争)。 防止这种冲突的方法就是当资源被一个任务使用时,在其上加锁。第一个访问某项资源的任务必须锁定这项资源,使其他任务在其被解锁之前,就无法访问它了,而在其被解锁之时,另一个任务就可以锁定并使用它了。

synchronized的锁是什么?
任意对象都可以作为同步锁。所有对象都自动含有单一的锁(监视器)。
同步方法的锁:静态方法(类名.class)、非静态方法(this)
同步代码块:自己指定,很多时候也是指定为this或类名.class

注意:
必须确保使用同一个资源的多个线程共用一把锁,这个非常重要,否则就无法保证共享资源的安全
一个线程类中的所有静态方法共用同一把锁(类名.class),所有非静态方法共用同一把锁(this),同步代码块(指定需谨慎)

释放锁的操作

当前线程的同步方法、同步代码块执行结束。
当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行。
当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束。
当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁。

不会释放锁的操作

线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行
线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程,挂起,该线程不会释放锁(同步监视器)。
应尽量避免使用suspend()和resume()来控制线程

Lock(锁)

从JDK 5.0开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当。

java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁。

话不多说,代码呈上,请笑纳

class A{
	private final ReentrantLock lock = new ReenTrantLock();
	public void m(){
		lock.lock();
		try{
			//保证线程安全的代码;
		}
		finally{
			lock.unlock();
		}
	}
}

注意:如果同步代码有异常,要将unlock()写入finally语句块

synchronized 与 Lock 的对比

  1. Lock是显式锁(手动开启和关闭锁,别忘记关闭锁),synchronized是隐式锁,出了作用域自动释放
  2. Lock只有代码块锁,synchronized有代码块锁和方法锁
  3. 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)

线程的通信

wait() 与 notify() 和 notifyAll()

1)wait():
令当前线程挂起并放弃CPU、同步资源并等待,使别的线程可访问并修改共享资源,而当前线程排队等候其他线程调用notify()或notifyAll()方法唤醒,唤醒后等待重新获得对监视器的所有权后才能继续执行。

2)notify():
唤醒正在排队等待同步资源的线程中优先级最高者结束等待

3)notifyAll ():
唤醒正在排队等待资源的所有线程结束等待.

话不多说,来道经典的消费者与生产者经典题

生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。

代码献上,请笑纳,嘿嘿

package com.lipeng.thread;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 生产者与消费者,当产品大于20的时候,停产
 * 反之生产
 * 
 * @author Administrator
 *
 */

class Consumer implements Runnable{
	
	private Waiter w;
	
	public Consumer(Waiter w) {
		this.w = w;
	}
	
	@Override
	public void run() {
		
		while(true) {
			System.out.println("消耗了一个产品,i="+w.i);
			w.consumeOneProduce();
		}
		
	}
}


class Producter implements Runnable{
	public int i = 0;
	public Waiter w;
	
	public Producter(Waiter w){
		this.w = w;
	}
	

	@Override
	public void run() {
		while(true) {
			System.out.println("生产了一个产品,i="+w.i);
			w.addProduce();
		}
	}
}

class Waiter{
	
	public int i = 0;
	public Lock lock = new ReentrantLock();
	
	public synchronized void addProduce() {
		if(i >= 20) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else {
			i++;
			notifyAll();
		}
	}
	
	public synchronized void consumeOneProduce() {
		
		if(i <= 0) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else {
			i--;
			notifyAll();
		}
	}
}

public class ConsumerAndProducter {
	
	public static void main(String[] args) {
		Waiter w = new Waiter();
		new Thread(new Producter(w)).start();
		new Thread(new Consumer(w)).start();
		
	}
}

这里还有一道题,可以练习,如果需要的话,嘿嘿
模拟银行取钱的问题
1.定义一个Account类
1)该Account类封装了账户编号(String)和余额(double)两个属性
2)设置相应属性的getter和setter方法
3)提供无参和有两个参数的构造器
4)系统根据账号判断与用户是否匹配,需提供hashCode()和equals()方法的重写
2.提供两个取钱的线程类:小明、小明’s wife
1)提供了Account类的account属性和double类的取款额的属性
2)提供带线程名的构造器
3)run()方法中提供取钱的操作
3.在主类中创建线程进行测试。考虑线程安全问题。

jdk1.5创建线程 && 线程池

创建线程第三种方式

Future接口
可以对具体Runnable、Callable任务的执行结果进行取消、查询是否完成、获取结果等。
FutrueTask是Futrue接口的唯一的实现类
FutureTask 同时实现了Runnable, Future接口。它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值

大鹏鸟,不废话,代码献上给大家

class ThreeThread implements Callable<String>{

	@Override
	public String call() throws Exception {
		
		return "three thread";
	}
	
}

public class CreateThread extends Thread{
	
	public static void main(String[] args) {
		FirstThead t1 = new FirstThead();
		t1.start();
		Thread t2 = new Thread(new SecondThread());
		t2.start();
		ThreeThread t3 = new ThreeThread();
		FutureTask<String> task = new FutureTask<String>(t3);
		new Thread(task).start();
		
		try {
			String rs = task.get();
			System.out.println(rs);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	
	}
}

线程池

背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,
对性能影响很大。

思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完
放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交
通工具。

好处:
提高响应速度(减少了创建新线程的时间)
降低资源消耗(重复利用线程池中线程,不需要每次都创建)
便于线程管理
corePoolSize:核心池的大小
maximumPoolSize:最大线程数
keepAliveTime:线程没有任务时最多保持多长时间后会终止

JDK 5.0起提供了线程池相关API:ExecutorService 和 Executors

ExecutorService:
真正的线程池接口。常见子类ThreadPoolExecutor
void execute(Runnable command) :执行任务/命令,没有返回值,一般用来执行Runnable
Future submit(Callable task):执行任务,有返回值,一般又来执行

Callable
void shutdown() :关闭连接池
Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池
Executors.newCachedThreadPool():创建一个可根据需要创建新线程的线程池
Executors.newFixedThreadPool(n); 创建一个可重用固定线程数的线程池
Executors.newSingleThreadExecutor() :创建一个只有一个线程的线程池
Executors.newScheduledThreadPool(n):创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值