文章是阅读《Java多线程编程核心技术》和《Java并发编程的艺术》写的,建议大家都读读,个人意见,
先完成核心技术的阅读,再去读并发编程艺术,感觉并发编程艺术比核心技术深。
从工作开始就发现自己的多线程只了解基础,我想好多刚开始Java开发的人员也多多线程了解的不多,工作起来才发现
多线程多么重要,没别的学起来才是硬道理。学什么都要系统的学一次,别想着偷懒,只了解某一个知识的某一点,那样
只会让自己学的东西越来越乱。
1:进程:现代操作系统一次程序的执行,是程序再一个数据集上运行的过程
eg:打开QQ,再QQ上做各种操作,都是完成再一个进程。
2:线程:一个进程中执行的一个子任务。现代操作系统执行程序的最小单元,
多线程的优点就不在多说:最大利用CPU资源,更好的编程模型。
Java自带了对多线程的支持,我们可以很方便的实现多线程
1:实现Runable接口
2:继承Thread类,
查看源码可以发现,Thread类就是实现了Runable接口的类,所以两种方法其实是一种方法,本质一样。
public class MyThead extends Thread {
@Override
public void run () {
super.run();
System.out.println("MyThread");
}
}
public class MyRunable implements Runable{
@Override
public void run () {
super.run();
System.out.println("MyRunable");
}
}
//main函数执行
public static void main(String [] args) {
MyThread myThead = new MyThread();
myThread.start() //多线成开始执行
myThread = new MyRunable();
myThread.start();
}
注:多线程的执行顺序与代码执行顺序或调用顺序无关,计算机系统会自己安排运行的时间段,
start方法通知“线程规划器”这个线程准备好了,等待系统安排时间来调用线程的run方法。
1:Thread():
2:Thread(Runable able) 分配新的Thread对象
3:Thread(Runable target, String name) name:为线程指定名字
4:Thread(String name)
5:Thread(ThreadGroup group, Runable target) :为线程指定线程组
6:Thread(ThreadGroup group, Runable target, String name);
7:Thread(ThreadGroup group, Runable target, String name, long stackSize)
long指定线程堆栈的大小。
8:Thread(Threadgroup group, String name)
自定义线程中实例变量对其他线程有共享和不共享之分,多个线程之间的共享数据
是很重要的一点。
1:不共享变量,每个线程单独享有自己的变量,互不交叉
eg:
public class MyThread extends Thread{
private int count = 5;
public MyThread(String name){
super(); this.setName(name);
}
@override
public void run(){
super.run();
while(count > 0){
count--;
System.out.println("由" + this.currentThread().getName() +
"计算, count =" + count);
}
}
}
//运行main函数
public class Run{
public static void main(String[] args){
MyThread a = new MyThread("A");
MyThread b = new MyThread("B");
a.start(); b.start();
}
}
上例子因为每个线程a b都是新建的对象,对象里的每一个count都是每个线程独有的,不会出现交叉,所以不会出现
共享变量,不会出现线程安全,
2:共享变量
public class Run{
public static void main(String [] args){
MyThread myThread = new MyThread("A");
Thread a = new Thread(myThread, "A");
Thread b = new Thread(myThread, "B");
a.start();
b.start();
}
}
上个例子是利用Thread类的构造函数,利用一个实例对象建立两个线程,这时两个线程共享一个实例对象,对象中的
变量也被两个线程共享,这时候就会出现共享变量的线程安全问题。
指多个线程对同一个对象的同一个实例变量进行操作时会出现值被更改,值不同步的情况,进而影响程序执行的流程。
public class MyThread extends Thread{
public MyThread(){
System.out.println(Thread.currentThread().getName());
}
@override
public void run(){
System.out.println(Thread.currentThread().getName());
}
}
public class Run{
public static void main(String [] args){
MyThread a = new MyThread(); //这里因为是主线程调用则输出为main
a.start(); //这里会调用run方法,但是是子线程调用,run方法会输出Thread-0
a.run(); //这里虽然调用run,但是普通的方法调用没有开启线程,run方法会输出main
}
}
this.isAlive(); myThread.isAlive();
Thread.sleep(1000);
Java有3中退出线程的方法。
public class Run(){
public static void main(String [] args){
MyThread a= new MyThread();
a.start();
a.interrupt();//设置中断标志位
a.interrupted();// 测试当前线程是否中断,虽然是a对象调用的,但是interrupted方法是被main
(当前线程)调用的,所以会返回false,
若在a线程的run方法中调用interrupted方法就会返回true,因为a线程已将被interrupt标记中断。
a.interrupted();// 再次调用返回还是false,因为main线程没有被中断
但若这个方法再次在a的run方法中调用就会返回false,因为第一次执行会清楚中断标志位。
}
}
isInterrupted():只是判断线程是否中断,
a.isInterrupted();返回true,
suspend()暂停线程, resume()恢复线程。
setPriority();设置线程的优先级,优先级越高,得到的CPU资源越多,优先级1~10,别的级别会报异常。
当A线程启动B线层时,B线程的优先级与A相同。
Java中分两种线程,用户线程和守护线程。
守护线程是一种特殊的线程,它是守护着用户线程,当没有用户线程活跃时,守护线程自动销毁。垃圾回收线程就是
典型的守护线程。setDaemon设置线程为守护线程
eg: myThread.setDaemon(true);