多线程:
1.什么是线程
线程是指程序在运行的过程中,能够执行程序代码的一个执行单元.java语言中的线程有四种状态:运行-就绪-挂起-结束.
2.线程与进程的区别.
进程:指一段正在执行的程序.
线程有时也被称之为轻量级的进程,它是程序执行的最小单元.一个进程可以拥有多个线程.各个线程之间共享程序的内存空间(代码段 数据段 堆空间)以及一些进程级的文件(如:打开的文件),但是各个线程拥有自己的栈空间.在操作系统级别上,程序的执行都是以进程为单位的,而每个进程中通常会有多个线程互不影响的并发执行.
3.为什么使用多线程.
a.提高执行效率,减少程序的响应时间.因为单线程执行的过程只有一个有效的操作序列,如果某个操作很耗时,(或者等待网络响应),此时程序就不会响应鼠标或者键盘的操作,如果使用多线程,就可以将耗时的线程分配到一个单独的线程上执行,从而使程序具备更好的交互性.
b.与进程相比,线程的创建和切换开销更小.因为开启一个新的进程需要分配一个独立的地址空间,建立许多数据结构来维护代码块等信息,而运行同一个进行的线程开销就很小.同时多线程在数据共享方面效率非常高.
c.市场上的服务器的配置都是CPU或者是多核计算机,具备使用多线程的能力,单个线程使用就无法重复利用计算机资源,造成资源浪费.
d.利用多线程可以简化程序的结构,使程序便于理解和维护.
4.同步和异步的区别.
在多线程的环境中,通常会遇到数据共享的问题,为了确保共享资源的正确性和安全性,就必须对共享资源进行同步处理(也就是锁机制).对共享数据进行同步操作(增删改),就必须要获得每个线程对象的锁(this锁),这样可以保证同一时刻只有一个线程对其操作,其他线程要想对其操作需要排队等候并获取锁.当然在等待队列中优先级最高的线程才能获得该锁,从而进入共享代码区.
java语言在同步机制中提供了语言级的支持,可以通过syschronized关键字来实现同步,但是该方法以很大的开销作为代价,有时候会造成死锁,所以同步机制不是越多越好,要避免所谓的同步控制.
实现同步的方法有两种:
第一种:同步方法(this锁)
第二种:同步代码块,(this锁或者自定义锁)当使用this锁时,就与同步方法共享同一锁,只有当this锁(第一种)释放,第二种才可以使用.同时同步代码块的范围小于同步方法,建议使用,相比之下能够提高性能.
使用多线程:
1.继承thread类
MyThread.java
public class MyThread extends Thread{
@Override
public void run{
super.run();
system.out.println("MyThread");
}
}
Run.java
public class Run{
public static void main(String [] args){
MyThread myThread = new MyThread();
myThread.start();
system.out.println("运行结束");
}
}
注:线程是一个子任务,CPU以不确定的方式,或者是以随机时间来调用线程中的run()方法.
2.实现Runnable接口
推荐使用Runable接口,java是单继承多实现.
MyRunnable.java
public class MyRunnable implements Runnable{
@Override
public void run{
Sytem.out.println("MyRunnable");
}
}
Run.java
public class Run{
public static void main (String [] args){
Runnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
System.out.println("运行结束!");
}
}
实例变量和线程安全.
定义线程类中的实例变量针对其他线程可以有共享和不共享之分.
第一种:
不共享数据的情况:
MyThread.java
public class MyThread extends Thread{
private int count = 5;
public MyThread{
super();
this.setName(name);
}
@Override
public void run{
super.run();
while(count > 0){
count -- ;
system.out.println("由"+MyThread.currentThread().getName()+"计算,count="+count);
}
}
}
Run.java
public class Run{
public static void main(String [] args){
MyThread a = new MyThread("A");
MyThread b = new MyThread("B");
MyThread c = new MyThread("C");
a.start();
b.start();
c.start();
}
}
注:可以看出每一个线程都有属于自己的一个实例变量count,他们之间是互不影响.
第二种:
共享数据的情况:
MyThread.java
public class MyThread extends Thread{
private int count = 5;
@Override
public void run{
super.run();
count -- ;
system.out.println("由"+MyThread.currentThread().getName()+"计算,count="+count);
}
}
Run.java
public class Run{
public static void main(String [] args){
MyThread a = new MyThread("A");
MyThread b = new MyThread("B");
MyThread c = new MyThread("C");
MyThread d = new MyThread("D");
MyThread e = new MyThread("E");
a.start();
b.start();
c.start();
d.start();
e.start();
}
}
注:
在大多数jvm中,count--操作有三布:
a 取的原有的count值
b 计算i -1
c 对i进行赋值
所以出现多个线程的时候就会出现问题.
解决办法:
使用关键字syschronized关键字.
在run方法之前加上syschronized关键字.
4.一些常用的方法.
4.1 currentThread()
返回当前正在执行的线程对象的引用
4.2 getId()
返回此线程的标识符
4.3 getName()
返回此线程的名字
4.4 getPrority()
返回此线程的优先级
4.5 isAlive()
测试这个线程是否处于活动状态
4.6 sleep(long millis)
使当前正在执行的线程以指定的毫秒数"休眠"(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性.
4.7 interrupt()
中断这个线程
4.8 isterrupted()和isInterrupted()
interrupted():测试当前线程是否已经是中断状态,执行后具有状态标志清除为false的功能
isterrupted():测试线程Thread对相关是否已经是中断状态,但不清楚状态标志.
4.9 setName(String name)
将此线程的名称更改为等于参数name;
4.10 isDaemon()
测试这个线程是否是守护线程
4.11 setDaemon(boolean on)
将此线程标记为daemon线程或者是用户线程
4.12 join()
在很多情况下主线程生成并启动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就需要用到join()方法了.
join的作用:"等待该线程终止",这里需要理解的是主线程等待的是子线程的终止,也就是子线程在调用了join()方法后面的代码,只用等待了子线程结束了才能执行.
4.13 yield()
作用是放弃当前的CPU资源,将它让给其他的任务去占用CPU时间.
注意:放弃的事件不确定,可能一会就会重新获得CPU的时间片.
4.14 setProprity(int newProprity)
更改此线程的优先级
5.如果停止一个线程.
stop(),suspend(),resume() 已经被弃用。
5.1 使用interrupt()方法.
MyThread.java
public class MyThread extends Thread{
@Override
public void run{
super.run();
for(int i=0;i<5000;i++){
system.out .println("i"+(i+1));
}
}
}
public class Run{
public static void main (String [] args){
try {
MyThread myThread = new MyThread();
myThread.start();
Thread.sleep(2000);
thread.interrupt();
}catch(InterruptException exception){
System.out.println("main catch");
e.printlnStackTrace();
}
}
}
注:线程不会终止。
MyThread.java
public class MyThread extends Thread{
@Override
public void run{
super.run();
for(int i=0;i<5000;i++){
if(this.interrupted()){
system.out.println("已经结束");
break;
}
system.out .println("i"+(i+1));
}
}
}
public class Run{
public static void main (String [] args){
try {
MyThread myThread = new MyThread();
myThread.start();
Thread.sleep(2000);
thread.interrupt();
}catch(InterruptException exception){
System.out.println("main catch");
e.printlnStackTrace();
}
}
}
for循环虽然已经停止,但是for循环下面的语句还是会执行,说明线程还是未被停止。
5.2 使用return停止线程。
MyThread.java
public class MyThread extends Thread{
@Override
public void run{
while(true){
if(this.interrupted()){
System.out.println("停止了");
return;
}
System.out.println("timer="+System.currentTimeMilles());
}
}
}
public class Run{
public static void main (String [] args){
MyThread myThread = new MyThread();
myThread.start();
Thread.sleep(200);
t.interrupt();
}
}
6. 线程的优先级。
每个线程都有各自的优先级。线程的优先级可以在程序中表明该线程的重要性。如果有多线程处于就绪状态,系统会根据各自的优先级来决定首先使用哪个线程进入运行状态。 但这个并不表明优先级低的得不到运行,只是运行的几率比较低。
线程的优先级具有继承性,比如A线程启动B线程,A线程的优先级和B线程的优先级是一样的。
线程的优先级具有随机性,线程优先级比较高的并不是每一次都先执行的。
Thread类中包含的成员变量代表了线程的某些优先级。
Thread.MIN_PROPRITY (常数1),
Thread.NORM_PROPRITY(常数5),
Thread.MAX.PROPRITY(常数10)
其中每个线程的优先级都在1-10之间,在默认情况下,线程的优先级都是常数5.
Java多线程的分类:
用户线程:
运行在前台 执行具体的任务。如程序的主线程,连接网络的子线程等都是用户线程。
守护线程:
运行在后台 为其他前台线程服务,也可以说守护线程是jvm中非守护线程的佣人。
特点:
一旦所有的用户线程都结束运行,守护线程会随着jvm一起结束工作。
应用:
数据库连接池中的检测线程,jvm虚拟机启动后的检测线程。
最常见的守护线程:
垃圾回收线程
7.2如何设置守护线程
可以通过调用Thread的setDaemon(true)方法设置当前的线程为守护线程.
注意:
a.setDaemon(true)必须
532

被折叠的 条评论
为什么被折叠?



