1、多线程:一个应用程序有多条执行路径
进程:正在执行的应用程序,是系统进行资源分配和调用的独立单位
线程:是进程中的单个顺序控制流,是一条执行路径
单线程:一个应用程序只有一条执行路径
多线程:一个应用程序有多条执行路径
多进程的意义?
提高CPU的使用率
多线程的意义?
提高应用程序的使用率
2、Java程序的运行原理及JVM的启动是多线程的吗?
3、多线程的实现方案A:Java命令去启动JVM,JVM会启动一个进程,该进程会启动一个主线程
B:JVM的启动是多线程的,因为它最低有两个线程启动了,主线程和垃圾回收线程
A:继承Thread类
步骤:
a.自定义类MyThread继承Thread类
b.B:MyThread类里面重写run()
c.创建对象
d.启动线程:对象名.start()
public class MyThreadDemo { public static void main(String[] args) { MyThread my1 = new MyThread(); MyThread my2 = new MyThread(); my1.start(); //调用第一个线程 my2.start(); //调用第二个线程 } } class MyThread extends Thread { public MyThread() { } public MyThread(String name) { super(name); } @Override public void run() { //重写的方法 for (int x = 0; x < 100; x++) { System.out.println(getName() + ":" + x); } } }
B:实现Runnable接口
步骤:
a.自定义类MyRunnable实现Runnable接口
b.重写run()方法
c.创建MyRunnable类的对象
d.创建Thread类的对象,并把C步骤的对象作为构造参数传递
public class MyRunnableDemo { public static void main(String[] args) { // 创建MyRunnable类的对象 MyRunnable my = new MyRunnable(); Thread t1 = new Thread(my, "张三"); Thread t2 = new Thread(my, "李四"); t1.start(); t2.start(); } } class MyRunnable implements Runnable { @Override public void run() { for (int x = 0; x < 10; x++) { // 由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用 System.out.println(Thread.currentThread().getName() + ":" + x); } } }
4、获取线程名称
A;获取
B:设置public final String getName():获取线程的名称
public final void setName(String name):设置线程的名称
C:当前线程
5、线程的调度和优先级问题public static Thread currentThread():返回当前正在执行的线程对象
Thread.currentThread().getName() 当前线程名称
A:线程的调度
B:获取和设置线程优先级a:分时调度
b:抢占式调度 (Java采用的是该调度方式)
a:默认是5
b:范围是1-10
c:方法
public final int getPriority():返回线程对象的优先级
public final void setPriority(int newPriority):更改线程的优先级
6、线程的控制(常见方法)
A:休眠线程
public static void sleep(long millis)
B:加入线程
public final void join():等待该线程终止
C:礼让线程
public static void yield():暂停当前正在执行的线程对象,并执行其他线程;让多个线程的执行更和谐,但是不能靠它保证一人一次
D:后台线程
public final void setDaemon(boolean on):将该线程标记为守护线程或用户线程
E:终止线程
public final void stop():让线程停止,过时了,但是还可以使用
public void interrupt():中断线程。 把线程的状态终止,并抛出一个InterruptedException
7、线程的生命周期
A:新建
B:就绪
C:运行
D:阻塞
E:死亡
8、多线程安全问题的原因
9、同步解决线程安全问题A:是否有多线程环境
B:是否有共享数据
C:是否有多条语句操作共享数据
A:同步代码块
synchronized(对象) {
}需要被同步的代码;
这里的锁对象可以是任意对象
B:同步方法
把同步加在方法上
这里的锁对象是this
C:静态同步方法
把同步加在方法上
这里的锁对象是当前类的字节码文件对象(反射再讲字节码文件对象)
10、电影票同步安全的案列
public class SellTicketDemo { public static void main(String[] args) { // 创建资源对象 SellTicket st = new SellTicket(); // 创建三个线程对象 Thread t1 = new Thread(st, "窗口1"); Thread t2 = new Thread(st, "窗口2"); Thread t3 = new Thread(st, "窗口3"); // 启动线程 t1.start(); t2.start(); t3.start(); } } class SellTicket implements Runnable { // 定义100张票 private static int tickets = 100; // 定义同一把锁 private Object obj = new Object(); private Demo d = new Demo(); private int x = 0; @Override public void run() { while (true) { if (x % 2 == 0) { synchronized (SellTicket.class) { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票 "); } } } else { sellTicket(); } x++; } } private static synchronized void sellTicket() { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票 "); } } } class Demo { }
11、线程安全的类
A:StringBuffer
B:Vector
C:Hashtable
D:如何把一个线程不安全的集合类变成一个线程安全的集合类
用Collections工具类的方法即可
public static <T> List<T> synchronizedList(List<T> list)
12、锁对象Lock
A:方法
void lock(): 获取锁
void unlock():释放锁
B:代码
public class SellTicket implements Runnable { // 定义票 private int tickets = 100; // 定义锁对象 private Lock lock = new ReentrantLock(); @Override public void run() { while (true) { try { // 加锁 lock.lock(); if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票"); } } finally { // 释放锁 lock.unlock(); } } } }
13、线程组
A:把多个线程组合到一起
B:线程的方法
public final ThreadGroup getThreadGroup() 获取所属的线程组
C:线程组的方法
public final String getName() 获取所属线程组的名称
14、线程池
A:好处:
线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用
B:实现
a:创建一个线程池对象,控制要创建几个线程对象
public static ExecutorService newFixedThreadPool(int nThreads)
b:哪种线程可以执行线程组
Runnable对象或者Callable对象代表的线程
C:调用方法
Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)
D:代码
public class ExecutorsDemo { public static void main(String[] args) { // 创建一个线程池对象,控制要创建几个线程对象。 // public static ExecutorService newFixedThreadPool(int nThreads) ExecutorService pool = Executors.newFixedThreadPool(2); // 可以执行Runnable对象或者Callable对象代表的线程 pool.submit(new MyRunnable()); pool.submit(new MyRunnable()); //结束线程池 pool.shutdown(); } }
C:Callable接口
这是实现多线程的第三种方式
代码体现:
/* * 线程求和案例 */ public class MyCallable implements Callable<Integer> { private int number; public MyCallable(int number) { this.number = number; } @Override public Integer call() throws Exception { int sum = 0; for (int x = 1; x <= number; x++) { sum += x; } return sum; } }
public class CallableDemo { public static void main(String[] args) throws InterruptedException, ExecutionException { // 创建线程池对象 ExecutorService pool = Executors.newFixedThreadPool(2); // 可以执行Runnable对象或者Callable对象代表的线程 Future<Integer> f1 = pool.submit(new MyCallable(100)); Future<Integer> f2 = pool.submit(new MyCallable(200)); // V get() Integer i1 = f1.get(); Integer i2 = f2.get(); System.out.println(i1); System.out.println(i2); // 结束 pool.shutdown(); } }
15、定时器
A:定时器:可以让我们在指定的时间做某件事情,还可以重复的做某件事情
B:依赖Timer和TimerTask这两个类:
Timer:定时
public Timer()
public void schedule(TimerTask task,long delay) 表示多少毫秒后执行定时任务
public void schedule(TimerTask task,long delay,long period) 表示每隔delay毫秒后第一次执行,然后每隔period毫秒后一直执行
public void cancel() 终止此计时器,丢弃所有当前已安排的任务
TimerTask:任务
C:代码体现
public class TimerDemo { public static void main(String[] args) { // 创建定时器对象 Timer t = new Timer(); // 3秒后执行爆炸任务 //结束任务 t.schedule(new MyTask(t), 3000); } } // 做一个任务 class MyTask extends TimerTask { private Timer t; public MyTask(){} public MyTask(Timer t){ this.t = t; } @Override public void run() { System.out.println("beng,爆炸了"); t.cancel(); } }