1. 进程和线程的区别
进程:正在进行的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。
线程:进程内部的一条执行路径或者一个控制单元。
区别:一个进程至少有一个线程;进程在执行过程中拥有独立的内存单元,而多个线程共享内存
2. 多线程利弊
利:解决了多个程序同时运行的问题,提高效率
弊:会导致效率降低,因为线程的执行是靠cpu的来回切换
3. 多线程的实现方法
根据多线程应用程序继承或实现对象的不同采用两种方式:一种是直接继承Java线程类Thread;另一种是定义并执行对象实现Runnable接口。
A:继承Thread类
定义一个类继承Thread类
复写Thread类中的run()方法,将线程的任务代码封装到run()方法中
直接创建Thread类中的子类对象,创建线程
调用start()方法,开启线程
B:实现 Runnable接口
定义一个类 实现Runnable接口
覆盖接口的run()方法,将线程的任务代码封装到run方法中
创建Runnable接口的子类对象作为参数传递给Thread类的构造函数,创建Thread类对象
调用start()方法,启动线程
两种方法的区别:
实现Runnable接口避免了单继承的局限性;
继承Thread类线程代码存放在Thread子类的run方法中,实现Runnable接口线程代码存放在接口的子类的run方法中
4. 线程状态:
新建:new一个Thread对象或者其子类对象就是创建一个线程,当一个线程对象被创建,但是没有开启,这个时候,
只是对象线程对象开辟了内存空间和初始化数据。
就绪:新建的对象调用start方法,就开启了线程,线程就到了就绪状态。
在这个状态的线程对象,具有执行资格,没有执行权。
运行:当线程对象获取到了CPU的资源。
在这个状态的线程对象,既有执行资格,也有执行权。
冻结:运行过程中的线程由于某些原因(比如wait,sleep),释放了执行资格和执行权。
当然,他们可以回到运行状态。只不过,不是直接回到。 而是先回到就绪状态。
死亡:当线程对象调用的run方法结束,或者直接调用stop方法,就让线程对象死亡,在内存中变成了垃圾。
5. 多线程安全问题
A 原因:当程序的多条语句在操作线程共享数据时,由于线程的随机性导致一个线程的多条语句,执行了一部分还没执行结束,
另一个线程抢到cpu执行权参与进来执行,此时就导致共享数据发生错误。
B 解决方法:对多条操作共享数据的语句进行同步,一个线程在执行过程中其他线程不可以参与进来
6.同步的前提及利弊
前提:保证两个以上线程
多个线程同时使用同一个锁,即多条语句操作线程共享数据
保证同步中只有一个线程运行
利:解决多线程的安全问题
弊:多线程都需要判断锁,比较消耗资源
同步有两种表现形式:同步函数和同步代码块;同步函数使用this锁, 同步函数被静态修饰后,使用的锁是该对象的类的字节码文件,同步代码块可以使用任意对象的锁
如下售票的例子:
饿汉式
懒汉式
8. 死锁:同步嵌套同步,并且锁不一样
9.多线程间通信:多个线程在操作同一个资源,但是操作动作不同。
A:为什么要通信
多线程并发执行的时候,如果需要制定线程等待或者唤醒指定线程,那么就需要通信。比如生产者消费者的问题,生产一个消费一个,生产的时候需要负责消费的进程等待,生产一个完成后需要唤醒负责消费的线程,同时让自己 处于等待,消费的时候负责消费的线程被唤醒,消费完生产的产品后又将等待的生产线程唤醒,然后处于等待。这样来回通信,以达到生产一个消费一个的目的。
B:如何通信
在同步代码块中,使用锁对象的wait()方法可以让当前线程等待,直到有其他线程唤醒为止。使用锁对象的notify()方法可以唤醒一个等待的线程,或者notifyAll唤醒所有等待的线程。多线程间通信用sleep很难实现,睡眠时间很难把握。
消费者生产者例子
10. wait()、sleep()、notify()、notifyAll()
wait()使一个线程处于等待状态,并且释放所持有的对象的lock;
sleep()使一个正在运行的线程处于睡眠状态,是一个静态方法,捕捉InterruptedException异常
notify()唤醒一个处于等待的线程,调用此方法时并不能确切的唤醒某一个等待状态的线程,而是由JVM确定,一般是最先开始等待的线程,不是按照优先级。
notifyAll()唤醒所以处于等待状态的线程,并不是给所有唤醒线程一个对象锁而是让它们竞争。
wait()、notify()、notifyAll()这些操作线程的方法定义在Object类中:只存在于同步中;必须指定所属锁 ,即被那个锁调用这些方法;而锁可以是任意对象,所以任意对象调用的方法就定义在Object中。
11. 其他方法
停止线程:stop方法已经过时
中断线程:void interrupt()中断状态将被清除,同时收到一个InterruptedException
守护线程:setDaemon(boolean on)主线程结束,守护线程自动结束
void join()等待该线程终止:当线程A执行到B线程的join方法时,A会等到B执行结束,A才执行
yield()方法:暂停当前正在执行的线程对象,并执行其他线程
进程:正在进行的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。
线程:进程内部的一条执行路径或者一个控制单元。
区别:一个进程至少有一个线程;进程在执行过程中拥有独立的内存单元,而多个线程共享内存
2. 多线程利弊
利:解决了多个程序同时运行的问题,提高效率
弊:会导致效率降低,因为线程的执行是靠cpu的来回切换
3. 多线程的实现方法
根据多线程应用程序继承或实现对象的不同采用两种方式:一种是直接继承Java线程类Thread;另一种是定义并执行对象实现Runnable接口。
A:继承Thread类
定义一个类继承Thread类
复写Thread类中的run()方法,将线程的任务代码封装到run()方法中
直接创建Thread类中的子类对象,创建线程
调用start()方法,开启线程
B:实现 Runnable接口
定义一个类 实现Runnable接口
覆盖接口的run()方法,将线程的任务代码封装到run方法中
创建Runnable接口的子类对象作为参数传递给Thread类的构造函数,创建Thread类对象
调用start()方法,启动线程
两种方法的区别:
实现Runnable接口避免了单继承的局限性;
继承Thread类线程代码存放在Thread子类的run方法中,实现Runnable接口线程代码存放在接口的子类的run方法中
4. 线程状态:
新建:new一个Thread对象或者其子类对象就是创建一个线程,当一个线程对象被创建,但是没有开启,这个时候,
只是对象线程对象开辟了内存空间和初始化数据。
就绪:新建的对象调用start方法,就开启了线程,线程就到了就绪状态。
在这个状态的线程对象,具有执行资格,没有执行权。
运行:当线程对象获取到了CPU的资源。
在这个状态的线程对象,既有执行资格,也有执行权。
冻结:运行过程中的线程由于某些原因(比如wait,sleep),释放了执行资格和执行权。
当然,他们可以回到运行状态。只不过,不是直接回到。 而是先回到就绪状态。
死亡:当线程对象调用的run方法结束,或者直接调用stop方法,就让线程对象死亡,在内存中变成了垃圾。
5. 多线程安全问题
A 原因:当程序的多条语句在操作线程共享数据时,由于线程的随机性导致一个线程的多条语句,执行了一部分还没执行结束,
另一个线程抢到cpu执行权参与进来执行,此时就导致共享数据发生错误。
B 解决方法:对多条操作共享数据的语句进行同步,一个线程在执行过程中其他线程不可以参与进来
6.同步的前提及利弊
前提:保证两个以上线程
多个线程同时使用同一个锁,即多条语句操作线程共享数据
保证同步中只有一个线程运行
利:解决多线程的安全问题
弊:多线程都需要判断锁,比较消耗资源
同步有两种表现形式:同步函数和同步代码块;同步函数使用this锁, 同步函数被静态修饰后,使用的锁是该对象的类的字节码文件,同步代码块可以使用任意对象的锁
如下售票的例子:
class Ticket implements Runnable
{
private int tick = 1000;
Object ob = new Object();
public void run()
{
while(true)
{
synchronized(ob)
{
if(tick>0)
{
try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
System.out.println(Thread.currentThread().getName()+" "+tick--);
}
}
}
}
}
class TicketDemo
{
public static void main(String args[])
{
Ticket t = new Ticket();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
7. 单例设计模式饿汉式
class Single //饿汉式
{
private Single(){} //构造方法私有,不让其他类建立该类对象
private static final Single s = new Single();//自己建立一个对象
public static Single getInstance()//提供一个公共访问方式
{
return s;
}
}
懒汉式
class Single //懒汉式
{
private Single(){}
private static final Single s;
public static Single getInstance()
{
if(s == null)
{
synchronized(Single.class)//避免线程安全问题
{
if(s == null)
s = new Single();
}
}
return s;
}
}
8. 死锁:同步嵌套同步,并且锁不一样
9.多线程间通信:多个线程在操作同一个资源,但是操作动作不同。
A:为什么要通信
多线程并发执行的时候,如果需要制定线程等待或者唤醒指定线程,那么就需要通信。比如生产者消费者的问题,生产一个消费一个,生产的时候需要负责消费的进程等待,生产一个完成后需要唤醒负责消费的线程,同时让自己 处于等待,消费的时候负责消费的线程被唤醒,消费完生产的产品后又将等待的生产线程唤醒,然后处于等待。这样来回通信,以达到生产一个消费一个的目的。
B:如何通信
在同步代码块中,使用锁对象的wait()方法可以让当前线程等待,直到有其他线程唤醒为止。使用锁对象的notify()方法可以唤醒一个等待的线程,或者notifyAll唤醒所有等待的线程。多线程间通信用sleep很难实现,睡眠时间很难把握。
消费者生产者例子
class ProducerConsumeDemo
{
public static void main(String args[])
{
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class Resource
{
private String name;
private boolean flag = false;
private int count = 1;
public synchronized void set(String name)
{
while(flag)
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.name = name+" "+count++;
System.out.println(Thread.currentThread().getName()+" 消费者 "+this.name);
flag = true;
this.notifyAll();
}
public synchronized void out()
{
while(!flag)
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 生产者 "+this.name);
flag = false;
this.notifyAll();
}
}
class Producer implements Runnable
{
private Resource res;
Producer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
res.set(" 商品 ");
}
}
}
class Consumer implements Runnablehttp://write.blog.youkuaiyun.com/postedit/8773950
{
private Resource res;
Consumer (Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
res.out();
}
}
}
10. wait()、sleep()、notify()、notifyAll()
wait()使一个线程处于等待状态,并且释放所持有的对象的lock;
sleep()使一个正在运行的线程处于睡眠状态,是一个静态方法,捕捉InterruptedException异常
notify()唤醒一个处于等待的线程,调用此方法时并不能确切的唤醒某一个等待状态的线程,而是由JVM确定,一般是最先开始等待的线程,不是按照优先级。
notifyAll()唤醒所以处于等待状态的线程,并不是给所有唤醒线程一个对象锁而是让它们竞争。
wait()、notify()、notifyAll()这些操作线程的方法定义在Object类中:只存在于同步中;必须指定所属锁 ,即被那个锁调用这些方法;而锁可以是任意对象,所以任意对象调用的方法就定义在Object中。
11. 其他方法
停止线程:stop方法已经过时
中断线程:void interrupt()中断状态将被清除,同时收到一个InterruptedException
守护线程:setDaemon(boolean on)主线程结束,守护线程自动结束
void join()等待该线程终止:当线程A执行到B线程的join方法时,A会等到B执行结束,A才执行
yield()方法:暂停当前正在执行的线程对象,并执行其他线程