多线程总结上篇链接
1.单例模式
1.1饿汉式
🍀备注:
????单例模式,只能创建一个对象;这一个方式时安全的—>对象的创建只执行过一次
🍀饿汉式理解化记忆:
????在静态方法外部直接以static的方式创建对象,只创建一次,在main()方法里面每次创建对象的时候,均使用第一次new()的对象。
public class SingletonTest1 {
public static void main(String[] args) {
Bank bank1 = Bank.getInstance();
Bank bank2 = Bank.getInstance();
System.out.println(bank2 == bank1);
}
}
class Bank{
private Bank(){
}
private static Bank instance = new Bank();
public static Bank getInstance(){
return instance;
}
}
1.2懒汉式
🍀理解:
在创建对象时,先设置为null,在静态方法内,判断是否有对象,然后创建
🍀出现安全问题原因(理解很重要):
????可能会有多个线程同时进入,第一个线程还没完成new对象的时候,第二个线程也进来了,也会认为此时没有对象,也会new()一个对象,这时就会new两个对象,所以是不安全的即创建了多个对象,并不是一个对象
????好处:延迟对象的创建 ????坏处:目前是不安全的
🍀原有的方式是不安全的:
public class SingletonTest2 {
public static void main(String[] args) {
Order o1 = Order.getInstance();
Order o2 = Order.getInstance();
System.out.println(o2 == o1);
}
}
懒汉式 不着急创建对象就不急着创建--懒汉式
class Order{
private Order(){
}
private static Order instance = null;
public static Order getInstance(){
if (instance == null){
instance = new Order();
return instance;
}
return instance;
}
}
🍀在解决安全性问题之后: 使用synchronized()代码块方法解决
class Bank{
private Bank(){
}
private static Bank instance = null;
public static Bank getInstance(){
if (instance == null){
synchronized (Bank.class){
if (instance == null){
instance = new Bank();
}
}
}
return instance;
}
}
public class BankTest {
public static void main(String[] args) {
Bank b1 = Bank.getInstance();
Bank b2 = Bank.getInstance();
System.out.println(b1 == b2);
}
}
2.JDK5后,新加的两种解决线程安全
2.1解决多线程安全实现方式一:实现Callable接口
对于初学者:先重点掌握前两种线程安全的处理方式,这两种稍作理解
🍀具体理解:
待补充…
🍀解决步骤:(按照步骤实现)
1.创建Callable接口的实现类 2.将需要执行的代码放到call()方法中 3.创建Callable接口实现类的对象 4.将Callable接口实现类的对象作为参数传递到FutureTask的构造器中,创建FutureTask的对象 5.将FutureTask的对象作为参数传递到Thread的构造器中,创建Thread对象,并且调用Threa的start() 6.获取Callable接口实现类中重写call方法的返回值
🍀实现样例:
class NumThread implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
if (i % 2 == 0){
sum +=i;
System.out.println(i);
}
}
return sum;
}
}
public class ThreadTest {
public static void main(String[] args) {
NumThread numThread = new NumThread();
FutureTask futureTask = new FutureTask(numThread);
new Thread(futureTask).start();
try {
Object o = futureTask.get();
System.out.println("总和为"+o);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
🍀问题:如何理解实现Callable接口的方式创建多线程比实现Runnable接口创建多线程的方式强大?
1.call()可以有返回值 2.call()可以抛出异常,被外面的操作捕获,获取异常的信息 3.Callable是支持泛型的
2.2解决多线程安全实现方式二:使用线程池
🍀背景:
经常创建和销毁、使用量特别大的资源,比如并发情况下的线程, 对性能影响很大。
🍀思路:
提前创建好多个线程,放入线程池中,使用时直接获取,使用完 放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交 通工具。
🍀好处:
提高响应速度(减少了创建新线程的时间) 降低资源消耗(重复利用线程池中线程,不需要每次都创建) 便于线程管理 corePoolSize:核心池的大小 maximumPoolSize:最大线程数 ? keepAliveTime:线程没有任务时最多保持多长时间后会终止
🍀实现步骤:
1.提供指定线程数量的线程池
执行方法: ExecutorService service = Executors.newFixedThreadPool(线程数量);
2.执行指定的线程操作,需要提供实现Runnable接口或Callable接口实现类的对象
执行方法:service.execute(Callable接口实现类);
3.关闭线程池
执行方法: service.shutdown();
🍀具体理解:
待后续学习后补充…
🍀实现样例:
class NumberThread implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}
class NumberThread1 implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
if (i % 2 != 0) {
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}
class NumberThread2 implements Callable {
@Override
public Object call() throws Exception {
int num = 0;
for (int i = 1; i <= 100 ; i++) {
if (i % 2 == 0){
num += i;
}
}
return num;
}
}
public class ThreadPool {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(new NumberThread());
service.execute(new NumberThread1());
FutureTask futureTask1 = (FutureTask) service.submit(new NumberThread2());
FutureTask futureTask = new FutureTask(new NumberThread2());
new Thread(futureTask).start();
try {
Object o = futureTask.get();
System.out.println(o);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
service.shutdown();
}
}
|