码迷,mamicode.com
首页 > 编程语言 > 详细

Java 多线程

时间:2020-11-26 14:41:04      阅读:7      评论:0      收藏:0      [点我收藏+]

标签:image   提交   lang   str   mic   down   线程状态   check   inter   

创建线程

方式一:继承Thread

  • 自定义一个类继承Thread类
  • 重写Thread的run方法,把自定义线程的任务代码定义在run方法上
  • 创建Thread子类的对象,并且调用start方法启动一个线程
public class MyThread extends Thread {
	public void run() {
		for (int i = 0; i < 100; i++)
			System.out.println(getName() + i);
	}
}

// test
    		MyThread my1=new MyThread();//设置线程名
		MyThread my2=new MyThread();
		my1.setName("线程1 ");
		my2.setName("线程2 ");
		my1.start();
		my2.start();

技术图片

方式二: 实现Runnable接口。

Thread类使用静态代理实现,Thread构造函数接收一个实现Runnable接口的类作为代理类
Thread类本身继承自Runnable接口

  • 自定义一个类实现Runnable接口。
  • 实现Runnable接口中的run方法,把自定义线程的任务代码定义在run方法上
  • 创建Runable实现类 的对象
  • 创建Thread对象,并且把Runnable实现类的对象作为参数传递
  • 调用Thread对象的start方法开启线程。
public class DeamonDemo implements Runnable{

	@Override
	public void run() {
		for(int i = 0;i<100;i++)
			System.out.println(Thread.currentThread().getName()+"---"+i);
	}

}

// test
public class DeamonTest {
	public static void main(String[] args) {
		DeamonDemo d = new DeamonDemo();
		
		Thread d1 = new Thread(d);
		Thread d2 = new Thread(d);

		d1.start();
		d2.start();

	}
}

方式三:实现Callable接口

Callable是线程池的方式创建线程,可以获取到执行函数的返回值,还可以在执行时抛出异常

  • 实现Callable接口,Callable是一个泛型接口,指定call函数返回值类型
  • 实例化实现了Callable接口类
  • 创建线程池Executors.newFixedThreadPool(3),指定线程池大小
  • 提交执行,executor.submit(testCallable1),传递实现了Callable接口类
  • 获取执行结果,executor.submit提交后可获取执行结果
  • 关闭线程池,executorService.shutdown();
public class TestCallable<T> implements Callable<T> {

    @Override
    public T call() throws Exception {
        for (int cnt = 0; cnt < 100;cnt++) {
            System.out.println(Thread.currentThread().getName()+" :cnt = " + cnt);
        }
        return null;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        for (int cnt = 0; cnt < 100;cnt++) {
            System.out.println(Thread.currentThread().getName()+" :cnt = " + cnt);
        }

        // 创建线程类
        TestCallable<Object> testCallable1 = new TestCallable<>();

        // 创建线程池,初始化线程池大小
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        // 提交执行
        Future<Object> future = executorService.submit(testCallable1);

        // 获取执行结果
        Object result = future.get();

        // 服务关闭
        executorService.shutdown();
    }
}

守护线程

  • 设置守护线程,一旦主线程结束就结束守护线程
DeamonDemo d = new DeamonDemo();
		
		Thread d1 = new Thread(d);
		Thread d2 = new Thread(d);
				
		d1.setDaemon(true);  //  设置守护线程
		d2.setDaemon(true);
		
		d1.start();
		d2.start();

		for(int i = 0;i<10;i++){
			//打印main线程(主线程)线程名
			System.out.println(Thread.currentThread().getName()+"---"+i);
		}

技术图片

设置线程优先级

  • IllegalArgumentException
  • void setPriority()
  • int getPriority():优先级范围1-10 默认5
		PriorityDemo p = new PriorityDemo();

		Thread tp1 = new Thread(p);
		Thread tp2 = new Thread(p);
		Thread tp3 = new Thread(p);

		tp1.setName("xyg");
		tp2.setName("wdf");
		tp3.setName("OoO");
		
		tp1.setPriority(10);  //  最高优先级
		tp2.setPriority(1);
		tp3.setPriority(1);
		
		tp1.start();
		tp2.start();
		tp3.start();

技术图片

线程状态

  • 线程通过thread.getState()方法获取状态

线程的六种状态

  • NEW:未启动状态
  • RUNNABLE:执行中
  • BLOCKED:等待线程锁
  • WAITING:线程等待
  • TIMED_WAITING:线程睡眠
  • TERMINATED:完成执行
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        thread.start();

        while (true) {
            if (thread.getState() == Thread.State.TERMINATED) {
                break;
            }
            System.out.println("thread = " + thread.getState());
        }
    }

...
thread = TIMED_WAITING
thread = TIMED_WAITING
thread = RUNNABLE
thread = RUNNABLE
thread = TERMINATED

线程加入 join

  • 一旦有join()线程,其他线程必须等待
		JoinDemo p = new JoinDemo();

		Thread tp1 = new Thread(p);
		Thread tp2 = new Thread(p);
		Thread tp3 = new Thread(p);

		tp1.setName("xyg");
		tp2.setName("fuck");
		tp3.setName("wdnmd");

		tp1.setPriority(10);
		tp2.setPriority(1);
		tp3.setPriority(1);

		tp1.start();
		try {
			tp1.join();  //  其他线程等待该线程终止
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		tp2.start();
		tp3.start();

技术图片

线程等待和唤醒

等待唤醒机制:

  • wait() 让线程处于等待状态
  • notify() 唤醒等待的线程
  • wait()的线程被唤醒后,继续执行,wait()方法出现后,对应的线程就释放了锁对象

wait()和sleep()

  • wait()是Object类方法,释放锁对象
  • sleep()是Thread类的的静态方法,不释放锁对象
	public synchronized void set(String name, int age) {
		//如果有数据则等待
		if (flag) {
			try {
				wait();  //  线程等待
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		//设置值
		this.name=name;
		this.age=age;

		// 修改标记
		flag = true;
		notify();// 线程唤醒
	}
    
        ...

	public synchronized void get(){
		//如果没有数据就等待
		if(!flag){
			try {
				wait();  // 线程等待
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		System.out.println(name+" "+age);
		
		//修改标记
		flag=false;
		notify();  // 线程唤醒
	}

线程暂停

  • public static void yield()----Thread:暂停当前正在执行的线程,并执行其他线程
  • 使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的
  • 因为让步的线程还有可能被线程调度程序再次选中。
	public void run() {
		for(int i = 0;i<100;i++){
			System.out.println(Thread.currentThread().getName()+"---"+i);
			Thread.yield();  //执行其他线程
		}
	}

线程安全

多个线程操作同一个数据,解决:添加锁

同步代码块

  • 同步代码块的锁可以是任意的对象。 同步函数的锁是固定 的,非静态函数的锁对象是this对象。 静态函数的锁对象是class对象。
  • 锁对象必须是多线程共享的对象,否则锁不住
  • 在同步代码块或者是同步函数中调用sleep方法是不会释放锁对象的,如果是调用了wait方法是会释放锁对象的。
        ...
	public void run() {
			if (x%2==0) {
				//同步代码块
				synchronized (this) {// 多个线程使用同一个锁对象
					if (ticket > 0) {
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票。");
					}
				}
			} 

方法锁

  • 同步代码块的锁可以是任意的对象。 同步函数的锁是固定 的,非静态函数的锁对象是this对象。 静态函数的锁对象是class对象。

	public void run() {
            check();
        }
        ...
	//同步方法
	//同步方法的锁对象是this对象
	//静态同步方法的锁对象是 类名.class Class类型对象
	private synchronized void check() {
			if (ticket > 0) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票。");
			}
	}

Arraylist线程安全

  • 使用了同步代码块锁住了arraylist的添加
  • sleep为了解决主线程过早结束
public static void main(String[] args) {
        ArrayList<Object> objects = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            Thread thread = new Thread(() -> {
                synchronized (objects){
                    objects.add(Thread.currentThread().getName());
                }
            });
            thread.start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("objects = " + objects.size());
    }

Juc的线程安全集合

public class JucList {
    public static void main(String[] args) {
        CopyOnWriteArrayList<Object> objects = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 1000; i++) {
            Thread thread = new Thread(() -> {
                    objects.add(Thread.currentThread().getName());
            });
            thread.start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("objects = " + objects.size());
    }
}

重用锁 ReentrantLock

Java 多线程

标签:image   提交   lang   str   mic   down   线程状态   check   inter   

原文地址:https://www.cnblogs.com/xiongyungang/p/12495740.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!