java多线程知识个人总结诶
2014-10-09 15:21
495 查看
第一部分:概要说明
多线程是操作系统中的重要的理论知识,关于进程和线程有以下几个重要的知识:
1)、一个运行的java进程至少包括两个线程,一个是主线程,一个是垃圾回收线程、
2)、线程是指进程中的一个执行任务(控制单元),一个进程中可以运行多个线程,多个线程可共享数据。
3)、多进程是操作系统中同时运行的多个程序;多线程:在同一个进程中同时运行的多个任务;
4)、一个进程至少有一个线程,为了提高效率,可以在一个进程中开启多个执行控制单元即多个线程,使之并发运行。
5)、多线程的的一个重要特征就是随机性,是因为CPU按照时间片切换处理各个线程导致的,
多线程的作用是提高程序的运行效率,但是正是因为多线程之间要强点CPU资源,就会导致
线程的同步和异步,死锁等等情况的出现,而这些东西正是多线程中需要了解的东西。
线程和进程的区别:
1)、进程有独立的进程空间,进程中的数据存放空间(堆空间和栈空间)是独立的。
2)、线程的堆空间是共享的,栈空间是独立的,线程消耗的资源也比进程小,相互之间可以影响的。
第二部分:多线程的实现
创建线程有两种方式:
第一种方式是该类继承Thread类,重写run方法,然后创建线程对象,通过线程对象,调用start方法就能够实现。
下面的例子:
public class MultiThread extends Thread{
private String name;
public MultiThread(String name) {
this.name = name;
}
public static void main(String[] args) {
MultiThread ta = new MultiThread("A线程");
MultiThread tb = new MultiThread("B线程");
ta.start();
tb.start();
}
//重写Thread里面的run方法
public void run() {
for(int i=0;i<10;i++){
System.out.println(name+":运行"+i);
}
}
}
继承Thread类并不提倡使用,因为一个类只能继承一个类,这样就限制了类的拓展。
第二种方法是实现Runnable接口,并实现接口中的run方法。
例如下面的例子:
public class MultiThreadByRunnable implements Runnable {
private String name;
public MultiThreadByRunnable(String name) {
this.name = name;
}
public static void main(String[] args) {
MultiThreadByRunnable ta = new MultiThreadByRunnable("A线程");
MultiThreadByRunnable tb = new MultiThreadByRunnable("B线程");
Thread t1 = new Thread(ta);
Thread t2 = new Thread(tb);
t1.start();
t2.start();
}
//重写Thread里面的run方法
public void run() {
for(int i=0;i<10;i++){
System.out.println(name+":运行"+i);
}
}
}
使用接口的方式,如要需要多线程的对象放入到Thread对象中。因为一个类能够实现多个接口这样就解决了
无法多继承的问题。
一般线程生命周期的五种状态
新建(new Thread)
当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动,也没有占用资源)。
例如:Thread t1=new Thread();
就绪(runnable)
线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。
例如:t1.start();
运行(running)
线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。
死亡(dead)
当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。
线程终止分为:
自然终止:正常运行run()方法后终止。
异常终止:调用stop()方法让一个线程终止运行。
堵塞(blocked)
由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。
正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。
正在等待:调用wait()方法。(调用motify()方法回到就绪状态)
被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复)
join方法:调用join方法的线程对象强制运行,或者说联合执行,该线程强制运行期间,
其他线程无法运行,必须等到该线程结束后其他线程才可以运行。
在run方法中调用:
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"正在运行!"+i);
if(i == 25){
try {
new Thread(new MyThreadDemo(),"wangwu").join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
setDaemon方法
后台线程:处于后台运行,任务是为其他线程提供服务。也称为“守护线程”或“精灵线程”。JVM的垃圾回收就是典型的后台线程。
特点:若所有的前台线程都死亡,后台线程自动死亡。
设置后台线程:Thread对象setDaemon(true);
setDaemon(true)必须在start()调用前。否则出现IllegalThreadStateException异常;
前台线程创建的线程默认是前台线程;
判断是否是后台线程:使用Thread对象的isDaemon()方法;
并且当且仅当创建线程是后台线程时,新线程才是后台线程。
sleep方法:线程休眠,让执行的线程暂停一段时间,进入阻塞状态,放弃占用CPU资源。
sleep(long milllis) throws InterruptedException:毫秒
sleep(long millis,int nanos)throws InterruptedException:毫秒,纳秒
调用sleep()后,在指定时间段之内,该线程不会获得执行的机会。
控制线程之优先级
每个线程都有优先级,优先级的高低只和线程获得执行机会的次数多少有关。
并非线程优先级越高的就一定先执行,哪个线程的先运行取决于CPU的调度;
默认情况下main线程具有普通的优先级,而它创建的线程也具有普通优先级。
Thread对象的setPriority(int x)和getPriority()来设置和获得优先级。
MAX_PRIORITY : 值是10
MIN_PRIORITY : 值是1
NORM_PRIORITY : 值是5(主方法默认优先级)
yield方法线程礼让;
暂停当前正在执行的线程对象,并执行其他线程;
Thread的静态方法,可以是当前线程暂停,但是不会阻塞该线程,而是进入就绪状态。
所以完全有可能:某个线程调用了yield()之后,线程调度器又把他调度出来重新执行。
多线程的安全问题的三种办法:
使用同步代码块:将执行的代码放到synchronized(){}中,参数一般是线程的名称或者是this。
public void run() {
for(int i=0;i<10;i++){
synchronized (name) {
System.out.println(name+":运行"+i);
}
}
}
调用synchronized方法:
public synchronized void ticketSell() {
for (int i = 0; i < 100; i++) {
if (num > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖出了第"
+ num-- + "张票!");
}
}
}
}
使用同步锁:
class FinalThreadDemo2 implements Runnable {
private int num = 50;
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
for (int i = 0; i < 100; i++) {
ticketSell();
}
}
public void ticketSell() {
lock.lock();
try{
//for (int i = 0; i < 100; i++) {
if (num > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖出了第"
+ num-- + "张票!");
}
//}
}finally{
lock.unlock();
}
}
}
线程通信:
wait():让当前线程放弃监视器进入等待,直到其他线程调用同一个监视器并调用notify()或notifyAll()为止。
notify():唤醒在同一对象监听器中调用wait方法的第一个线程。
notifyAll():唤醒在同一对象监听器中调用wait方法的所有线程。
await():等价于同步监听器的wait()方法;
signal():等价于同步监听器的notify()方法;
signalAll():等价于同步监听器的notifyAll()方法;
多线程经典例子:生产者和消费者问题,
/*
例子:设置属性
容易出现的问题是:
名字和性别不对应!
线程通信,很好!
*/
package com.demo.thread;
class Person{
private String name;
private String sex;
private Boolean isimpty = Boolean.TRUE;//内存区为空!
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void set(String name,String sex){
synchronized (this) {
while(!isimpty.equals(Boolean.TRUE)){//不为空的话等待消费者消费!
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name;//为空的话生产者创造!
this.sex = sex;
isimpty = Boolean.FALSE;//创造结束后修改属性!
this.notifyAll();
}
}
public void get(){
synchronized (this) {
while(!isimpty.equals(Boolean.FALSE)){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("姓名"+getName()+ ", "+"性别"+getSex());
isimpty = Boolean.TRUE;
this.notifyAll();
}
}
}
class Producer implements Runnable{
private Person p;
public Producer(Person p) {
super();
this.p = p;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if( i % 2 == 0){
p.set("zhangsan", "男");
}else{
p.set("lisi", "女");
}
}
}
}
class Consumer implements Runnable{
private Person p;
public Consumer(Person p) {
super();
this.p = p;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
p.get();
}
}
}
public class ThreadDemo6 {
public static void main(String[] args) {
Person p = new Person();
new Thread(new Producer(p)).start();
new Thread(new Consumer(p)).start();
}
}
多线程是操作系统中的重要的理论知识,关于进程和线程有以下几个重要的知识:
1)、一个运行的java进程至少包括两个线程,一个是主线程,一个是垃圾回收线程、
2)、线程是指进程中的一个执行任务(控制单元),一个进程中可以运行多个线程,多个线程可共享数据。
3)、多进程是操作系统中同时运行的多个程序;多线程:在同一个进程中同时运行的多个任务;
4)、一个进程至少有一个线程,为了提高效率,可以在一个进程中开启多个执行控制单元即多个线程,使之并发运行。
5)、多线程的的一个重要特征就是随机性,是因为CPU按照时间片切换处理各个线程导致的,
多线程的作用是提高程序的运行效率,但是正是因为多线程之间要强点CPU资源,就会导致
线程的同步和异步,死锁等等情况的出现,而这些东西正是多线程中需要了解的东西。
线程和进程的区别:
1)、进程有独立的进程空间,进程中的数据存放空间(堆空间和栈空间)是独立的。
2)、线程的堆空间是共享的,栈空间是独立的,线程消耗的资源也比进程小,相互之间可以影响的。
第二部分:多线程的实现
创建线程有两种方式:
第一种方式是该类继承Thread类,重写run方法,然后创建线程对象,通过线程对象,调用start方法就能够实现。
下面的例子:
public class MultiThread extends Thread{
private String name;
public MultiThread(String name) {
this.name = name;
}
public static void main(String[] args) {
MultiThread ta = new MultiThread("A线程");
MultiThread tb = new MultiThread("B线程");
ta.start();
tb.start();
}
//重写Thread里面的run方法
public void run() {
for(int i=0;i<10;i++){
System.out.println(name+":运行"+i);
}
}
}
继承Thread类并不提倡使用,因为一个类只能继承一个类,这样就限制了类的拓展。
第二种方法是实现Runnable接口,并实现接口中的run方法。
例如下面的例子:
public class MultiThreadByRunnable implements Runnable {
private String name;
public MultiThreadByRunnable(String name) {
this.name = name;
}
public static void main(String[] args) {
MultiThreadByRunnable ta = new MultiThreadByRunnable("A线程");
MultiThreadByRunnable tb = new MultiThreadByRunnable("B线程");
Thread t1 = new Thread(ta);
Thread t2 = new Thread(tb);
t1.start();
t2.start();
}
//重写Thread里面的run方法
public void run() {
for(int i=0;i<10;i++){
System.out.println(name+":运行"+i);
}
}
}
使用接口的方式,如要需要多线程的对象放入到Thread对象中。因为一个类能够实现多个接口这样就解决了
无法多继承的问题。
一般线程生命周期的五种状态
新建(new Thread)
当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动,也没有占用资源)。
例如:Thread t1=new Thread();
就绪(runnable)
线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。
例如:t1.start();
运行(running)
线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。
死亡(dead)
当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。
线程终止分为:
自然终止:正常运行run()方法后终止。
异常终止:调用stop()方法让一个线程终止运行。
堵塞(blocked)
由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。
正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。
正在等待:调用wait()方法。(调用motify()方法回到就绪状态)
被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复)
join方法:调用join方法的线程对象强制运行,或者说联合执行,该线程强制运行期间,
其他线程无法运行,必须等到该线程结束后其他线程才可以运行。
在run方法中调用:
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"正在运行!"+i);
if(i == 25){
try {
new Thread(new MyThreadDemo(),"wangwu").join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
setDaemon方法
后台线程:处于后台运行,任务是为其他线程提供服务。也称为“守护线程”或“精灵线程”。JVM的垃圾回收就是典型的后台线程。
特点:若所有的前台线程都死亡,后台线程自动死亡。
设置后台线程:Thread对象setDaemon(true);
setDaemon(true)必须在start()调用前。否则出现IllegalThreadStateException异常;
前台线程创建的线程默认是前台线程;
判断是否是后台线程:使用Thread对象的isDaemon()方法;
并且当且仅当创建线程是后台线程时,新线程才是后台线程。
sleep方法:线程休眠,让执行的线程暂停一段时间,进入阻塞状态,放弃占用CPU资源。
sleep(long milllis) throws InterruptedException:毫秒
sleep(long millis,int nanos)throws InterruptedException:毫秒,纳秒
调用sleep()后,在指定时间段之内,该线程不会获得执行的机会。
控制线程之优先级
每个线程都有优先级,优先级的高低只和线程获得执行机会的次数多少有关。
并非线程优先级越高的就一定先执行,哪个线程的先运行取决于CPU的调度;
默认情况下main线程具有普通的优先级,而它创建的线程也具有普通优先级。
Thread对象的setPriority(int x)和getPriority()来设置和获得优先级。
MAX_PRIORITY : 值是10
MIN_PRIORITY : 值是1
NORM_PRIORITY : 值是5(主方法默认优先级)
yield方法线程礼让;
暂停当前正在执行的线程对象,并执行其他线程;
Thread的静态方法,可以是当前线程暂停,但是不会阻塞该线程,而是进入就绪状态。
所以完全有可能:某个线程调用了yield()之后,线程调度器又把他调度出来重新执行。
多线程的安全问题的三种办法:
使用同步代码块:将执行的代码放到synchronized(){}中,参数一般是线程的名称或者是this。
public void run() {
for(int i=0;i<10;i++){
synchronized (name) {
System.out.println(name+":运行"+i);
}
}
}
调用synchronized方法:
public synchronized void ticketSell() {
for (int i = 0; i < 100; i++) {
if (num > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖出了第"
+ num-- + "张票!");
}
}
}
}
使用同步锁:
class FinalThreadDemo2 implements Runnable {
private int num = 50;
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
for (int i = 0; i < 100; i++) {
ticketSell();
}
}
public void ticketSell() {
lock.lock();
try{
//for (int i = 0; i < 100; i++) {
if (num > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖出了第"
+ num-- + "张票!");
}
//}
}finally{
lock.unlock();
}
}
}
线程通信:
wait():让当前线程放弃监视器进入等待,直到其他线程调用同一个监视器并调用notify()或notifyAll()为止。
notify():唤醒在同一对象监听器中调用wait方法的第一个线程。
notifyAll():唤醒在同一对象监听器中调用wait方法的所有线程。
await():等价于同步监听器的wait()方法;
signal():等价于同步监听器的notify()方法;
signalAll():等价于同步监听器的notifyAll()方法;
多线程经典例子:生产者和消费者问题,
/*
例子:设置属性
容易出现的问题是:
名字和性别不对应!
线程通信,很好!
*/
package com.demo.thread;
class Person{
private String name;
private String sex;
private Boolean isimpty = Boolean.TRUE;//内存区为空!
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void set(String name,String sex){
synchronized (this) {
while(!isimpty.equals(Boolean.TRUE)){//不为空的话等待消费者消费!
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name;//为空的话生产者创造!
this.sex = sex;
isimpty = Boolean.FALSE;//创造结束后修改属性!
this.notifyAll();
}
}
public void get(){
synchronized (this) {
while(!isimpty.equals(Boolean.FALSE)){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("姓名"+getName()+ ", "+"性别"+getSex());
isimpty = Boolean.TRUE;
this.notifyAll();
}
}
}
class Producer implements Runnable{
private Person p;
public Producer(Person p) {
super();
this.p = p;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if( i % 2 == 0){
p.set("zhangsan", "男");
}else{
p.set("lisi", "女");
}
}
}
}
class Consumer implements Runnable{
private Person p;
public Consumer(Person p) {
super();
this.p = p;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
p.get();
}
}
}
public class ThreadDemo6 {
public static void main(String[] args) {
Person p = new Person();
new Thread(new Producer(p)).start();
new Thread(new Consumer(p)).start();
}
}
相关文章推荐
- java多线程知识个人总结诶
- Java【多线程知识总结(1)】用Thread类创建线程
- Java【多线程知识总结(4)】通过实现Runnable接口创建线程
- Java【多线程知识总结(10)】线程通信之wait()与notify()的运用--模拟指挥官指挥2个连队交替轰炸战区
- 黑马程序员学习log第四篇基础知识:JAVA的面向对象之多线程总结
- java基础知识个人总结
- Java【多线程知识总结(2)】调用setDaemon(true)变成后台线程
- Java【多线程知识总结(8)】线程通信,wait()与notify()的运用
- Java【多线程知识总结(10)】线程通信之wait()与notify()的运用--模拟指挥官指挥2个连队交替轰炸战区<另外的写法>
- Java【多线程知识总结(9)】Timer类与TimerTask类的应用---模拟定时炸弹
- Java多线程基础知识总结笔记
- Java【多线程知识总结(3)】调用join()合并线程
- Java【多线程知识总结(7)】多线程同步问题-关于synchronized代码块和synchronized方法的应用
- Java【多线程知识总结】
- Java多线程编程总结笔记——一多线程基础知识
- Java【多线程知识总结(3)】调用join()合并线程
- Java【多线程知识总结(5)】比较继承Thread类创建线程和实现Runnable接口创建线程这两种方式
- Java【多线程知识总结(6)】使用Runnable接口创建多线程,处理同一个资源
- 黑马程序员_03Java多线程知识总结
- Java【多线程知识总结(2)】调用setDaemon(true)变成后台线程