- java线程的五大基本状态
- java线程创建的三种基本形式
继承Thread类重写run()方法
public class BallThread extends Thread{
public void run() {
System.out.println("线程正在执行");
}
}
public static void main(String[] args) {
BallThread ball = new BallThread();
ball.start();
}
- 实现接口Runnable,重写接口里的run()方法
public class MyRunnable implements Runnable{
public void run() {
System.out.println("线程正在执行");
}
public static void main(String[] args) {
MyRunnable m = new MyRunnable();//创建接口对象
Thread th = new Thread(m); //将接口对象当作参数传到Thread类里面
th.start();
}
- 匿名线程
public static void main(String[] args) {
new Thread(){
public void run(){
System.out.println("开启线程");
}
}.start();
}
使用线程注意:当所用类不需要继承其他类时,大多使用直接继承Thread,当线程需要继承其他类时,就以实现接口的方式,当线程逻辑较为简单时使用匿名线程的方式
- 线程的同步问题
- 1.同步方法
即有synchronized关键字修饰的方法。
由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,
内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
代码如:
public synchronized void save(){}
-
2.同步代码块
即有synchronized关键字修饰的语句块。
被该关键字修饰的语句块会自动被加上内置锁,从而实现同步
public int getCash(int cash) {
synchronized (this) { //注意这个锁里面的对象需要一致不然达不到锁的效果
if (cash > count) {
System.out.println("你的余额不足,请重新输入");
return -1;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
count = count - cash;
System.out.println("取钱成功,取钱额度为:" + cash + "余额为:" + count);
return count;
}
}
- 1. wait()与notify()/notifyAll()
调用sleep()和yield()的时候锁并没有被释放,而调用wait()将释放锁。这样另一个任务(线程)可以获得当前对象的锁,从而进入它的synchronized方法中。
只能在同步控制方法或同步块中调用wait()、notify()和notifyAll()。如果在非同步的方法里调用这些方法,在运行时会抛出IllegalMonitorStateException异常。
可以通过notify()/notifyAll(),或者时间到期,从wait()中恢复执行。
例如:
synchronized(obj) {
while(!condition) {
obj.wait();
}
obj.doSomething();
}
当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait()。
在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A :
synchronized(obj) {
condition = true;
obj.notify();
}
需要注意的概念是:
# 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj){...} 代码段内。
# 调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj){...} 代码段内唤醒A。
# 当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。
#如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。
#obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。
# 当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行
一,线程池的基本要素线程池一般需要一个线程管理类: ThreadPoolManager,其作用有:
1)提供创建一定数量的线程的方法。主线程调用该方法,从而创建线程。创建的线程执行自己的例程,线程的例程阻塞在任务抓取上。
2)提供对任务队列的操作的方法。主线程调用初始化任务队列的方法,然后在有任务的时候,调用提供的任务添加方法,将任务添入等待队列。当主线程调用任务的添加方法时,会触发等待的线程,从而使得阻塞的线程被唤醒,其抓取任务,并执行任务。线程池需要一个任务队列: List<Task>,其作用有:
提供任务的增删方法。而且该任务队列需要进行排他处理,防止多个工作线程对该任务队列进行同时的抓取操作或者主线程的加入与工作线程的抓取的并发操作。
线程池需要一个类似信号量的通知机制:wait -notify:工作线程调用wait阻塞在任务抓取上。主线程添加任务后,调用notify触发阻塞的线程。
线程池需要一个线程类:WorkThread,其作用有:
提供线程的例程。创建线程WorkThread后,需要抓取任务,并执行任务。这是线程的例程。
线程池需要一个任务类:Task,其作用有:
提供线程抓取并执行的任务目标。
。
public class BallThread extends Thread{
public void run() {
System.out.println("线程正在执行");
}
}
public static void main(String[] args) {
BallThread ball = new BallThread();
ball.start();
}
- 实现接口Runnable,重写接口里的run()方法
public class MyRunnable implements Runnable{ public void run() { System.out.println("线程正在执行"); }
public static void main(String[] args) { MyRunnable m = new MyRunnable();//创建接口对象 Thread th = new Thread(m); //将接口对象当作参数传到Thread类里面 th.start(); }
- 匿名线程
使用线程注意:当所用类不需要继承其他类时,大多使用直接继承Thread,当线程需要继承其他类时,就以实现接口的方式,当线程逻辑较为简单时使用匿名线程的方式public static void main(String[] args) { new Thread(){ public void run(){ System.out.println("开启线程"); } }.start(); }
- 线程的同步问题
- 1.同步方法
即有synchronized关键字修饰的方法。由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。代码如:public synchronized void save(){}
-
2.同步代码块即有synchronized关键字修饰的语句块。被该关键字修饰的语句块会自动被加上内置锁,从而实现同步
public int getCash(int cash) { synchronized (this) { //注意这个锁里面的对象需要一致不然达不到锁的效果 if (cash > count) { System.out.println("你的余额不足,请重新输入"); return -1; } try { Thread.sleep(100); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } count = count - cash; System.out.println("取钱成功,取钱额度为:" + cash + "余额为:" + count); return count; } }
- 1. wait()与notify()/notifyAll()
调用sleep()和yield()的时候锁并没有被释放,而调用wait()将释放锁。这样另一个任务(线程)可以获得当前对象的锁,从而进入它的synchronized方法中。只能在同步控制方法或同步块中调用wait()、notify()和notifyAll()。如果在非同步的方法里调用这些方法,在运行时会抛出IllegalMonitorStateException异常。可以通过notify()/notifyAll(),或者时间到期,从wait()中恢复执行。
例如:
synchronized(obj) {
while(!condition) {
obj.wait();
}
obj.doSomething();
}
当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait()。
在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A :
synchronized(obj) {
condition = true;
obj.notify();
}
需要注意的概念是:
# 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj){...} 代码段内。
# 调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj){...} 代码段内唤醒A。
# 当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。
#如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。
#obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。
# 当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行
一,线程池的基本要素线程池一般需要一个线程管理类: ThreadPoolManager,其作用有:
1)提供创建一定数量的线程的方法。主线程调用该方法,从而创建线程。创建的线程执行自己的例程,线程的例程阻塞在任务抓取上。
2)提供对任务队列的操作的方法。主线程调用初始化任务队列的方法,然后在有任务的时候,调用提供的任务添加方法,将任务添入等待队列。当主线程调用任务的添加方法时,会触发等待的线程,从而使得阻塞的线程被唤醒,其抓取任务,并执行任务。线程池需要一个任务队列: List<Task>,其作用有:
提供任务的增删方法。而且该任务队列需要进行排他处理,防止多个工作线程对该任务队列进行同时的抓取操作或者主线程的加入与工作线程的抓取的并发操作。
线程池需要一个类似信号量的通知机制:wait -notify:工作线程调用wait阻塞在任务抓取上。主线程添加任务后,调用notify触发阻塞的线程。
线程池需要一个线程类:WorkThread,其作用有:
提供线程的例程。创建线程WorkThread后,需要抓取任务,并执行任务。这是线程的例程。
线程池需要一个任务类:Task,其作用有:
提供线程抓取并执行的任务目标。
。