1.Java的多线程只需要类实现Runnable接口或者继承Thread父类即可
继承自Thread:
public class ThreadDemo1 {
public static void main(String[] args){
Demo demo = new Demo();
demo.start();
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
class Demo extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
实现Runnable接口:
public class ThreadDemo1 {
public static void main(String[] args){
Demo demo = new Demo();
demo.start();
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
class Demo extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
这两种方法各有利弊。简单来说,如果你确定当前的类就是作为一个单纯的线程来实现,不需要再继承其他任何类的时候,那么最好就用第一种方式,因为简单,而且可以直接就获得Thread所提供的各种方法,在类内部使用;反之,如果你需要继承其他类,或者将来可能会有这种需要,那么就用第二种方法。
第二种方法需要注意的地方是,当你实现了Runnable接口后,你仅仅是实现了该接口而已,你现在所有的只是一个run()方法,即使你生成一个对象来调用run()方法,和普通的方法调用也没什么两样,并不会创建一个新的线程。只有当你用Thread构造函数创建一个对象之后,这才是新创建了一个线程。
当你使用第二种方法的时候,可能你也想在类内部调用Thread所提供的一些方法,这时可以用Thread.currentThread()来获得当前线程的引用。
2.Thread的主要方法:
(1)run
(2)start:线程开始运行
(3)join:调用线程执行x.join(),表示调用线程等待x线程执行完
(4)sleep:当前线程休眠
(5)yield:当前线程出让CPU
(6)isInterrupted:是否处于中断状态
(7)interrupt:设置线程的中断状态
(8)interrupted:清除线程的中断状态
(9)setDeamon:设置是否守护线程
(10)setPriority:设置优先级
3.wait(), notify(), notifyAll()
这三个方法是Java同步的基础。
使用wait(),总是要最先想到,一定要用while循环来判断执行条件是否满足:
synchronized(obj) {
while(conditionIsNotMet) {
wait();
}
// Perform action approriate to condition
}
这样就可以保证在跳出等待循环之前条件将被满足,如果你被不相干的条件所通知(比如notifyAll()),或者在你完全退出循环之前条件已经改变,你被确保可以回来继续等待。
- synchronized
synchronized是将对象中所有加锁的方法(or代码块)锁定。由于同一时间只能有一个线程拥有对象的锁,这也就保证了互斥。
有两种加锁形式:
给代码块加锁:
synchronized(obj) {
// some codes here
}
给方法加锁:
public synchronized void method() {
// some codes here
}
一个简单的实例:
public class ThreadDemo3 {
public static void main(String[] arg){
Ticket ticket=new Ticket();
Thread t1 =new Thread(ticket,"窗口1");
Thread t2 =new Thread(ticket,"窗口2");
Thread t3 =new Thread(ticket,"窗口3");
Thread t4=new Thread(ticket,"窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class Ticket implements Runnable{
private int ticket=400;
@Override
public void run() {
while (true){
// synchronized (Ticket.class){
synchronized (this){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(ticket<=0)
break;
System.out.println(Thread.currentThread().getName()+"----卖出一张,剩余:"+--ticket);
}
}
}
}
//class Ticket implements Runnable{
// private int ticket=400;
// public synchronized void saleTicket(){
// try {
// Thread.sleep(1);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// if(ticket>0)
// System.out.println(Thread.currentThread().getName()+"----卖出了一张,剩余"+--ticket);
// }
// @Override
// public void run() {
// while (true){
// saleTicket();
// }
// }
//}
5.线程的四种状态:创建、就绪、死亡、阻塞。
通过调用sleep()使线程进入休眠状态。在这种情况下,线程在指定时间内不会运行
通过调用wait()使线程挂起,直到线程得到了notify()或notifyAll()消息,线程才会进入就绪状态
线程在等待输入/输出操作的完成,进入阻塞状态
线程试图在某个对象上调用其同步控制方法,但是对象锁不可用