多线程基本用法

1多线程创建方式

方法一:继承java.lang.Thread, 重写run()方法
Thread本质上也是实现了Runnable接口的一个实例,并且,启动线程的唯一方法就是通过Thread类的start()方法。调用start()方法,再重写run()方法就可以启动新线程并执行自己定义的run()方法。调用start()方法后并不是立即执行多线程代码,而是使得该线程变为可运行态,什么时候运行多线程代码是由操作系统决定的。

class MyThread extends Thread {
    private int tid;

    public MyThread(int tid) {
        this.tid = tid;
    }

    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; ++i) {
                Thread.sleep(1000); //每隔1000睡眠一下
                System.out.println(String.format("%d:%d", tid, i));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

//测试
public class Main {
    public static void main(String[] args) {
        new MyThread().start();
    }
}

方法二:实现java.lang.Runnable接口,重写run()方法

代码一:

public static void testThread() {
    for (int i = 0; i < 10; ++i) {
        final int finalI = i;
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for (int j = 0; j < 10; ++j) {
                        Thread.sleep(1000);
                        System.out.println(String.format("T2 %d: %d:", finalI, j));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
//测试
public static void main(String[] argv) {
    testThread();
}

代码二:

① 自定义类并实现Runnable接口,实现run()方法。
② 创建Thread方法,用实现Runnable接口的对象作为参数实例化该Thread对象。
③ 调用Thread的start()方法。
class MyThread implements Runnable {
		public void run(){
			System.out.println(“Thread body”);
		}
	}
	public class Test{
		public static void main(String[] args){
			MyThread thread = new MyThread();
			Thread t = new Thread(thread);
			t.start();
		}
	}

方式三:实现Callable接口,重写call()方法
属于Executor框架中的功能类,与Runnable接口功能类似,但提供了比Runnable接口更强大的功能,主要表现在:
① Callable可以在任务结束后提供一个返回值,Runnable不能。
② Callable中的call()方法可以抛出异常,Runnable的run()方法不能。
③ 运行Callable可以拿到一个Future对象,表示异步计算的结果,提供了检查计算是否完成的方法。由于线程属于异步计算模型,因此无法从别的线程中得到函数的返回值,在这种情况下,就可以使用Future来监视目标线程调用call()方法的情况,当调用Future的get()方法以获取结果时,当前线程就会阻塞,直到call()方法结束返回结果。

2 Synchronized 内置锁

   当Synchronized用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码,而这段代码也被称为临界区。
// synchronized(obj)锁住相应的代码段
public static void testSynchronized1() {
    synchronized (obj) {
        try {
            for (int j = 0; j < 10; ++j) {
                Thread.sleep(1000);
                System.out.println(String.format("T1 %d", j));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public static void testSynchronized2() {
    synchronized (new Object()) {
        try {
            for (int j = 0; j < 10; ++j) {
                Thread.sleep(1000);
                System.out.println(String.format("T2 %d", j));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
//测试
//参数 obj与new Object()为不同对象,因此两个内置锁互不干扰
//参数相同时(都为obj),两个内置锁互相干扰,一个执行完才执行另一个
public static void testSynchronized() {
    for (int i = 0; i < 10; ++i) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                testSynchronized1();
                testSynchronized2();
            }
        }).start();
    }
}

3 BlockingQueue 同步队列

//remove实现(implements Runnable接口,实现 run()方法)
class Consumer implements Runnable {
    private BlockingQueue<String> q;
    public Consumer(BlockingQueue<String> q) {
        this.q = q;
    }
    @Override
    public void run() {
        try {
            while (true) {
                System.out.println(Thread.currentThread().getName() + ":" + q.take());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
//insert实现
class Producer implements Runnable {
    private BlockingQueue<String> q;
    public Producer(BlockingQueue<String> q) {
        this.q = q;
    }
    @Override
    public void run() {
        try {
            for (int i = 0; i < 100; ++i) {
                Thread.sleep(1000);
                q.put(String .valueOf(i));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
//测试
public static void testBlockingQueue() {
    BlockingQueue<String> q = new ArrayBlockingQueue<String>(10);
    new Thread(new Producer(q)).start();
    new Thread(new Consumer(q), "Consumer1").start();
    new Thread(new Consumer(q), "Consumer2").start();
}
public static void main(String[] argv) {
        testBlockingQueue();
 }

结果:两条线程交替消费
在这里插入图片描述

4 ThreadLocal

ThreadLocal:线程局部变量,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据。即使是一个static成员,每个线程访问的变量是不同的。常见于web中存储当前用户到一个静态工具类,在线程的任何地方都可以访问到当前线程的用户。利用ThreadLocal可以防止线程访问同一个变量时发生混乱。

//ThreadLocal变量和普通变量
private static ThreadLocal<Integer> threadLocalUserIds = new ThreadLocal<>();
private static int userId;

//利用ThreadLocal存储用户信息
@Component
public class HostHolder {
    private static ThreadLocal<User> users = new ThreadLocal<User>();

    public User getUser() {
        return users.get();
    }

    public void setUser(User user) {
        users.set(user);
    }

    public void clear() {
        users.remove();;
    }
}

5 Executor

Executor :提供一个运行任务的框架,将任务和如何运行任务解耦,常用于提供线程池或定时任务服务.

// Executor
public static void testExecutor() {
    //ExecutorService service = Executors.newSingleThreadExecutor();单个线程
    ExecutorService service = Executors.newFixedThreadPool(2);//两个线程
    service.submit(new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i < 10; ++i) {
                try {
                    Thread.sleep(1000);
                    System.out.println("Executor1:" + i);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    });

    service.submit(new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i < 10; ++i) {
                try {
                    Thread.sleep(1000);
                    System.out.println("Executor2:" + i);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    });
}

部分结果:交替执行
在这里插入图片描述

6 Future

Future:返回异步结果、阻塞等待返回结果、获取线程中的exception

//测试
public static void testFuture() {
    ExecutorService service = Executors.newSingleThreadExecutor();
    Future<Integer> future = service.submit(new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            throw new IllegalArgumentException("异常");
        }
    });

    service.shutdown();
    try {
//get()方法可以当任务结束后返回一个结果,如果调用时,工作还没有结束,则会阻塞线
//程,直到任务执行完毕
        System.out.println(future.get());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

7 AtomicInteger

AtomicInteger:高并发的情况下,i++无法保证原子性,往往会出现问题,所以引入AtomicInteger类。

//普通变量和AtomicInteger变量的定义
private static int counter = 0;
private static AtomicInteger atomicInteger = new AtomicInteger(0);
//普通变量结果没有100,达到97
public static void testWithoutAtomic() {
    for (int i = 0; i < 10; ++i) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    for (int j = 0; j < 10; ++j) {
                        counter++;
                        System.out.println(counter);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
//AtomicInteger变量可以达到100
public static void testWithAtomic() {
    for (int i = 0; i < 10; ++i) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    for (int j = 0; j < 10; ++j) {
                        System.out.println(atomicInteger.incrementAndGet());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

public static  void testAtomic() {
    testWithAtomic();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值