java多线程的入门研究
一.多线程的核心概念
1.线程就是独立的执行路径;
2.在程序运行时,即使没有自己创建的线程,后台也会有多个线程,如主线程、gc线程
3.main()称之为主线程,为系统的入口,用于执行整个程序;
4.在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密关联的,先后顺序是不能人为的关于;
5.对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
6.线程会带来额外的开销,如cpu调度时间,并发控制时间;
7.每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
二.线程状态
线程状态:
- NEW:尚未启动的线程处于此状态。
- RUNNABLE:在java虚拟机中执行的线程处于此状态。
- BLOCKED:被阻塞等待监视器锁定的线程处于此状态。
- WAITTING:正在等待另一线程执行特定的动作线程处于此状态。
- TIMED_WAITTING:正在等待另一线程执行动作达到指定等待时间的线程处于此状态。
- TERMINATED:已退出的线程处于此状态。
线程方法:
方法 | 说明 |
---|---|
setPriority(int newPriority) | 更改线程的优先级 |
static void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠 |
void join | 等待该线程终止 |
static void yield() | 暂停当前正在执行的线程对象,并执行其他线程(礼让) |
void interrupt() | 中断线程,别用这个方式 |
boolean isAlive() | 测试线程是否处于活动状态 |
线程通信
方法名 | 作用 |
---|---|
wait() | 表示线程一直等待,直到其他线程通知,与sleep不通,会释放锁 |
wait(long timeout) | 指定等待的毫秒数 |
notify() | 唤醒一个处于等待状态的线程 |
notifyAll() | 唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度 |
a.停止线程(stop)
不推荐使用JDK提供的stop()、destroy()方法。【已废弃 】- 推荐线程自己停下来。
- 建议使用一个标志位进行终止变量,当flag=false,则终止线程运行。
示例:线程停止代码示例
public class ThreadStop implements Runnable{
private static boolean flag = true;
public void run() {
while(flag) {
System.out.println("我在疯狂的循环中---");
}
}
public static void main(String[] args) {
new Thread(new ThreadStop()).start();
for(int i = 0;i < 1000;i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i == 50) {
flag = false;
}
}
}
}
b.线程休眠(sleep)
- sleep(时间)指定当前线程阻塞的毫秒数;
- sleep存在异常InterruptedException;
- sleep时间达到后线程进入就绪状态;
- sleep可以模拟网络延时,倒计时等;
- 每一个对象都有一个锁,sleep不会释放锁;
c.线程礼让(yield)
- 礼让线程,让当前正在执行的线程暂停,但不阻塞;
- 让线程从运行状态转为就绪状态;
- 让cpu重新调度,礼让不一定成功!看cpu心情;
d.线程插队(Join)
- Join合并线程,待此线程执行完成后,在执行其他线程,其他线程阻塞
- 可以想象成插队
public class ThreadJoin implements Runnable{
public static void main(String[] args) {
Thread t = new Thread(new ThreadJoin());
t.start();
for (int i = 0; i < 500; i++) {
if (i == 20) {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("普通客户:"+i);
}
}
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("线程VIP:"+i);
}
}
}
e.线程的优先级
- java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。
- 线程的优先级用数字表示,范围从1~10
- Thread.MIN_PRIORITY = 1;
- Thread.MAX_PRIORITY = 10;
- Thread.NORM_PRIORITY = 5;
- 使用以下方式改变或获取优先级
- getPriority()
- setPriority(int xxx)
f.守护(daemon)线程
- 线程分为用户线程和守护线程(mian()线程代表用户线程,gc()代表守护线程)
- 虚拟机必须确保用户线程执行完毕
- 虚拟机不用等待守护线程执行完毕
- 如:后台记录操作日志,监控内存,垃圾回收等待…
public class ThreadDaemon{
public static void main(String[] args) {
// 打开守护线程
God god = new God();
Thread t = new Thread(god);
t.setDaemon(true);// true:代表开始守护线程,false:默认,代表用户线程
t.start();
new Thread(new People()).start();
}
}
class God implements Runnable{
public void run() {
while(true) {
System.out.println("---上帝在保护着你----");
}
}
}
class People implements Runnable {
@Override
public void run() {
for(int i = 0;i < 50;i++) {
System.out.println("----人民在快乐的生活着---");
}
}
}
三.多线程的三种创建方式
- extends Thread类;
- implements Runnable接口;
- implements Callable接口;
例1:extends Thread类;
public class Thread1 extends Thread{
private String name;
public Thread1 (String name) {
this.name = name;
}
public void run() {
while(true) {
System.out.println("我是一个兔子---");
}
}
public static void main(String[] args) {
new Thread1("张三").start();
}
}
例2: implements Runnable接口;
public class Thread2 implements Runnable{
private String name;
public Thread2 (String name) {
this.name = name;
}
public Thread2() {
}
public void run() {
while(true) {
name = Thread.currentThread().getName();
if(name.equals("张三")) {
for(int i = 0;i < 100;i++) {
System.out.println("---我是张三-"+i);
}
break;
}
if(name.equals("李四")) {
for(int i = 0;i < 100;i++) {
System.out.println("---我是李四-"+i);
}
break;
}
}
}
public static void main(String[] args) {
Thread2 t = new Thread2();
new Thread(t,"张三").start();
new Thread(t,"李四").start();
}
}
例3:implements Callable接口
public class Thread3 implements Callable<Boolean>{
private String name;
public Thread3 (String name) {
this.name = name;
}
public Thread3() {
}
public Boolean call() {
System.out.println("--"+name);
return true;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
Thread3 t1 = new Thread3("张三");
Thread3 t2 = new Thread3("李四");
Thread3 t3 = new Thread3("王五");
// 1.创建执行服务
ExecutorService ex = Executors.newFixedThreadPool(3);
// 2.提交执行
Future<Boolean> r1 = ex.submit(t1);
Future<Boolean> r2 = ex.submit(t2);
Future<Boolean> r3 = ex.submit(t3);
// 获取结果
boolean rs1 = r1.get();
boolean rs2 = r2.get();
boolean rs3 = r3.get();
// 关闭服务
ex.shutdownNow();
}
}
四.多线程其他扩展
a.多线程之Lambda表达式
- Lambda 规定接口中只能有一个需要被实现的方法,不是规定接口中只能有一个方法
- 语法形式为 () -> {},其中 () 用来描述参数列表,{} 用来描述方法体,-> 为 lambda运算符 ,读作(goes to)
代码示例:
for (int i = 0;i < 10000;i++) {
new Thread(
// lambda表达式
()->{
list.add(Thread.currentThread().getName());
}
).start();
}
}
b.多线程之ReentrantLock
public class ThreadLock implements Runnable{
public static void main(String[] args) {
ThreadLock t2 = new ThreadLock();
new Thread(t2).start();
new Thread(t2).start();
new Thread(t2).start();
new Thread(t2).start();
new Thread(t2).start();
new Thread(t2).start();
}
private int ticketNums = 10;
final transient ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while(true) {
try {
lock.lock();
if (ticketNums <= 0) {
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ticketNums--);
} finally {
lock.unlock();
}
}
}
}
c.多线程之JUC
1.CopyOnWriteArrayList
public class ThreadJucList {
public static void main(String[] args) {
// 理论上线程安全,实际存在删除操作的时候会存在数组越界的风险,固不是绝对的安全
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
for (int i = 0;i < 10000;i++) {
new Thread(
// lamda表达式
()->{
list.add(Thread.currentThread().getName());
}
).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("------list-size:"+list.size());
}
}
d.管程法
/**
* 测试:生产者消费者模型--》利用缓冲区解决:管程法
* 生产者、消费者、产品、缓冲区
*/
public class ThreadContainer {
public static void main(String[] args) {
SynContainer syn = new SynContainer();
new Thread(new Productor(syn)).start();
new Thread(new Consumer(syn)).start();
}
}
// 缓冲区
class SynContainer{
// 设置容器的大小
Chicken[] chickens = new Chicken[2];
// 容器的计数器
int count = 0;
//生产者放入产品
public synchronized void push(Chicken chicken) {
// 如果容器满了,就需要等待消费者消费
if (count == chickens.length) {
// 通知消费者消费,等待生产
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果没有满,我们就需要丢入产品
chickens[count] = chicken;
count++;
// 可以通知消费者消费了
this.notifyAll();
}
// 消费者消费产品
public synchronized Chicken pop() {
// 判断能否消费
if (count == 0) {
// 等待生产者生产,消费者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果可以消费
count--;
Chicken chicken = chickens[count];
// 吃完了,通知生产者生产
this.notifyAll();
return chicken;
}
}
// 生产者
class Productor implements Runnable{
SynContainer container;
public Productor(SynContainer container) {
this.container = container;
}
@Override
public void run() {
for (int i = 0;i < 10;i++) {
System.out.println("----生产者生产了-->"+i+"的鸡");
container.push(new Chicken(i));
}
}
}
// 消费者
class Consumer implements Runnable{
SynContainer container;
public Consumer(SynContainer container){
this.container = container;
}
@Override
public void run() {
for(int i = 0;i < 10;i++) {
System.out.println("---消费者消费了-->"+container.pop().numNo+"的鸡");
}
}
}
// 产品
class Chicken{
int numNo;
public Chicken(int numNo) {
this.numNo = numNo;
}
}
e.使用Runnable创建线程池
/**
* 使用线程池--Runnable
*/
public class ThreadPool implements Runnable{
public static void main(String[] args) {
// 1.创建服务,创建线程池
ExecutorService service = Executors.newFixedThreadPool(10);
// 2.执行
service.execute(new ThreadPool());
service.execute(new ThreadPool());
service.execute(new ThreadPool());
service.execute(new ThreadPool());
service.execute(new ThreadPool());
// 3.关闭链接
service.shutdown();
}
@Override
public void run() {
System.out.println("---我是线程池:"+Thread.currentThread().getName());
}
}