标签:
开始第二遍学习java了,发现有好多的知识点在之前学习的时候是不了解的。在java多线程的板块中,学到了除了继承Thread 实现runnable接口以外 还学到了第三种的基于线程池的实现callable接口的线程方式。感觉java真实博大精深。对java线程的笔记总结:
1:多线程
(1)多线程:一个应用程序有多条执行路径 进程:正在执行的应用程序 线程:进程的执行单元,执行路径 单线程:一个应用程序只有一条执行路径 多线程:一个应用程序有多条执行路径
多进程的意义?
提高CPU的使用率
多线程的意义?
提高应用程序的使用率
(2)Java程序的运行原理及JVM的启动是多线程的吗?
A:Java命令去启动JVM,JVM会启动一个进程,该进程会启动一个主线程。
B:JVM的启动是多线程的,因为它最低有两个线程启动了,主线程和垃圾回收线程。
* 两种方式的比较
B:获取和设置线程优先级
a:默认是5
b:范围是1-10
线程睡眠毫秒数
join:等待线程终止,等待线程执行完毕后其它的线程才可以运行
一定程度上让多个线程的执行和谐,不靠谱
public final void stop() 让线程停止,已过时
public void interrupt() 终止线程,并且抛出InterruptedException异常,并会执行后续的代码
创建线程对象的过程
有执行的条件和资格,没有执行权
有运行的资格,有执行权
没有执行资格,没有执行权
线程对象变成垃圾,等待被回收
(7)电影院卖票程序的实现
A:继承Thread类
B:实现Runnable接口
(8)电影院卖票程序出问题
A:为了更符合真实的场景,加入了休眠100毫秒。
B:卖票问题
a:同票多次
b:负数票
(9)多线程安全问题的原因(也是我们以后判断一个程序是否有线程安全问题的依据)
A:是否有多线程环境
B:是否有共享数据
C:是否有多条语句操作共享数据
synchronized(对象) {
需要被同步的代码;
}
这里的锁对象可以是任意对象。
把同步加在方法上。
这里的锁对象是this
把同步加在方法上。
这里的锁对象是当前类的字节码文件对象(反射再讲字节码文件对象)
- A:StringBuffer
- B:Vector
- C:Hashtable
- D:如何把一个线程不安全的集合类变成一个线程安全的集合类用Collections工具类的方法即可。
// 定义锁对象
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();
}
}
}
- 是指两个或者两个以上的线程在执行的过程中,因争夺资源产一种互相等待现象
- 同步代码块的嵌套案例
@Override
public void run() {
// 死锁代码
if (flag) {
// 同步嵌套
synchronized (MyLock.objA) {
System.out.println("if obja");
synchronized (MyLock.objB) {
System.out.println("if objb");
}
}
} else {
synchronized (MyLock.objB) {
System.out.println("else objb");
synchronized (MyLock.objA) {
System.out.println("else obja");
}
}
}
}
以学生作为资源来实现的
资源类:Student
设置数据类:SetThread(生产者)
获取数据类:GetThread(消费者)
测试类:StudentDemo
代码:
A:最基本的版本,只有一个数据。
B:改进版本,给出了不同的数据,并加入了同步机制
C:等待唤醒机制改进该程序,让数据能够实现依次的出现
wait() 线程等待后立即释放所持有的锁,被唤醒后在等待的位置继续执行
notify() 唤醒并不代表立马可以执行 线程会转为就绪状态 等待下一次执行
notifyAll() (多生产多消费)
Thread(ThreadGroup group, Runnable target, String name)
新建线程组代码:
// ThreadGroup(String name)
ThreadGroup tg = new ThreadGroup("这是一个新的组");
MyRunnable my = new MyRunnable();
// Thread(ThreadGroup group, Runnable target, String name)
Thread t1 = new Thread(tg, my, "林青霞");
Thread t2 = new Thread(tg, my, "刘意");
System.out.println(t1.getThreadGroup().getName());
System.out.println(t2.getThreadGroup().getName());
//通过组名称设置后台线程,表示该组的线程都是后台线程
tg.setDaemon(true);
程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。
public static ExecutorService newCachedThreadPool()
创建一个具有缓存功能的线程池
缓存:百度浏览过的信息再次访问
public static ExecutorService newFixedThreadPool(int nThreads)
创建一个可重用的,具有固定线程数的线程池
public static ExecutorService newSingleThreadExecutor()
创建一个只有单线程的线程池,相当于上个方法的参数是1
protected void shutdown()
顺序关闭线程池中的线程 这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
Future<?> submit(Runnable task)
Future submit(Callable task)
实现Callable接口 步骤和刚才演示线程池执行Runnable对象的差不多。 但是还可以更好玩一些,求和案例演示 好处: 可以有返回值 可以抛出异常 弊端: 代码比较复杂,所以一般不用
new Thread(){代码…}.start(); New Thread(new Runnable(){代码…}).start();
定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。在Java中,可以通过Timer和TimerTask类来实现定义调度的功能
Timer 一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。
public Timer()
public void schedule(TimerTask task, long delay)
public void schedule(TimerTask task,long delay,long period)
* TimerTask 任务类用于为Timer指定任务 public abstract void run()
public boolean cancel()
* 开发中
Quartz是一个完全由java编写的开源调度框架。线程的生命周期转换图:
标签:
原文地址:http://blog.csdn.net/probuing/article/details/51130537