多线程
进程就是应用程序的执行实例,有独立的内存空间和系统资源。
进程的特点:
1、是动态产生,动态销完的,动态的占用,动态的释放 2、是并发执行的 3、进程是独立
线程是进程内部的独立单元,在同一个进程里可以运行多个线程,然后使用的资源是它的进程的资源,cpu不会再单独给线程资源,它也可以单线独立执行,它是进程中执行运算的最小单位,真正在cpu上运行的是线程。线程同时执行的原理是线程抢占cpu的资源,同一个时间,只有一个线程在执行,其他的线程都在等待的状态,只是因为时间比较短,看到现象就是同时执行。一个线程可以创建一个线程,也可以删除一个线程。
线程分为:1、系统级的线程,就是系统分配的进程 2、用户级线程,程序来控制它的存亡,存在于用户空间
进程中至少包含一个线程,这叫主线程,在程序开始运行的时候就会创建的,但是可以创建其他的线程,我们创建的都不是主线程
什么是多线程:如果在一个进程同时运行了多个线程,用来完成不同的工作,则称之为“多线程”。
main()方法即为主线程入口。
方法:
线程对象.getName() 获得当前线程的对象的名字
Thread.currentThread() 得到当前线程对象
.setPriority(int newPriority) 更改线程的优先级,1~10,越高的优先执行的越快,1最低,默认优先级为5
sleep(long millis) 在指定的毫秒数内记当前正在执行的线程休眠,这是一个静态方法
jion() 让此线程强制执行完,才让其他的线程执行
yield() 暂停当前正在执行的线程对象,可执行其他线程,但是也不排除执行此线程,因为要看哪个线程抢到了cpu资源,这是静态方法
interrupt() 中断线程
isAive() 测试线程是否处于活动状态
调用run()方法,只有主线程一条执行路径
调用start()方法,多条线程执行路径
要创建线路就是要重写run方法,线程要做的事,都写在run方法里面。
步骤:
1、创建线程类,定义线程
2、创建线程类对象(使用Runnable接口实现,就要多使用Thread创建一个对象,将之前创建的线程类对象作为参数,放进线程中)
3、启动线程start方法,系统会帮程序创建一个线程,会调用run方法,如果是接口实现的线程,要使用创建的Thread对象去启动线程
4、终止线程
线程的创建:
1、继承java.lang.Thread类,Thread类也是实现Runnable接口的,所以一般比较简单的线程,就使用Thread类
相对于Runnable来说,比较简便,缺点是不可以再继承其他的类了,在Thread中,run方法里,如果给的对象为空的时候,run方法就不会执行
案例1:
package cn.lnm.exp1;
/**
* 这个是使用继承Thread类,去实现线程
* @author Administrator
*
*/
public class MyThread extends Thread {
@Override
//要去重写Thread类中的run方法,达到执行线程的操作,要实现线程操作的代码都是要写到run方法中的,或者写一个方法,然后在run方法中去调用此方法
public void run() {
for (int i = 0; i <10; i++) {
//Thread.currentThread().getName()这个是获得当前线程的名字
System.out.println(Thread.currentThread().getName()+"\t"+i);
}
}
public static void main(String[] args) {
//main方法是一条主线程,要在主线程中去启动其他的线程
MyThread t1=new MyThread();
t1.start();//要使用start()方法去实现线程的启动
MyThread t2=new MyThread();
t2.start();
}
}
2、实现java.lang.Runnable接口
多个线程可以共享一个资源(线程类对象)
案例2:
package cn.lnm.exp1;
public class MyRunnable implements Runnable{
@Override public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"\t"+i);
}
}
public static void main(String[] args) {
MyRunnable m1=new MyRunnable();
Thread t1=new Thread(m1);
t1.start();
Thread t2=new Thread(m1);
t2.start();
}
}
线程的同步:多个线程共享同一资源时,一个线程未完成全部操作的时候,其他线程修改的数据,造成数据不安全问题。可以使用同步代码块,或者同步方法(将run方法的代码块抽取出一个方法,使用synchronized去做修饰,再到run方法中去调用此方法),把会发生数据不一致的地主,加一把锁,让只有一个线程进去,让其他线程处于等待状态。
有synchronized修饰的线程都是安全的,效率会低,但是会数据安全,比如Hashtable、StringBuffered这些类都是线程安全的。
synchronized就是为当前的线程声明一个锁,当一个线程完成全部操作,其他线程才能进入。
案例3:这是锁定方法
package cn.lnm.exp1;
/**
* 火车票
* @author Administrator
*
*/
public class Ticket implements Runnable{
private int count=10;//记录剩余票数
private int num=0;//记录当前第几张票
@Override
public void run() {
qiang();
}
public synchronized void qiang() {
while(true){
//循环 当剩余票数为0时结束
if(count<=0){//如果剩余票数小于0就跳出循环
break;
}
//修改数据(剩余票数,抢到第几张票)
count--;
num++;
//网络延迟,使用线程休眠
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//显示信息,反馈用户抢到第几张票
System.out.println("抢到第"+num+"票,剩余"+count+"张票");
}
}
}
案例4:这是锁定代码块
@Override
public void run() {
while (true) {// 循环 当剩余票数为0时结束
synchronized (this) {
if (count <= 0) {// 如果剩余票数小于0就跳出循环
break;
}
// 修改数据(剩余票数,抢到第几张票)
count--;
num++;
// 网络延迟,使用线程休眠
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 显示信息,反馈用户抢到第几张票
System.out.println("抢到第" + num + "票,剩余" + count + "张票");
}
}
}
多个并发线程访问同一资源的同步代码块时
1.同一时刻只能有一个线程进入synchronized(this)同步代码块
2.当一个线程访问一个synchronized(this)
使用synchronized会发生死锁,死锁是程序中要避免的。死锁就是大家都想拿到对方的东西,但是却又不把自己的东西给出去造成的。
要避免死锁,就是要先释放自己的锁,或者尽量不同步方法,同步代码块的嵌套。