进程是系统中已经运行的程序实体,是线程的容器,一个进程中可以包含多条线程。进程间相互独立,同一进程的各线程间共享地址空间和其他资源。
线程是程序中一条单一顺序的控制流,就是进程中真正做事的。
区别:地址空间和其他资源(如打开文件):进程间相互独立,同一进程的各线程间共享。
用法选择:
1.需要频繁创建销毁的优先使用线程,因为对进程来说创建和销毁一个进程的代价是很大的。
2.线程的切换速度快,所以在需要大量计算,切换频繁时使用线程,还有耗时的操作时用使用线程可提高应用程序的响应。
3.要更稳定安全时,选择进程 or 要速度时,选择线程。
对于单核CPU来说,系统同一时刻只能干同一件事情,CPU会将它的时间分成很小的时间片轮,交替运行不同的程序,给人的错觉是同时在运行。
注意:一个特殊的状态:就绪。具备了执行资格,但是还没有获取资源。
a.继承Thread类,重写run方法
b.实现Runnable接口,重写run方法,启动时还是需要Thread包装一下。
/*
* 为什么需要多线程?
* 更加充分的利用CPU资源
*/
public class ThreadDemo1 extends Thread
{
public static void main(String[] args)
{
//java程序启动,就会默认创建一主(main)线程
System.out.println("当前线:"+Thread.currentThread().getName());
//创建线程
//进入新建状态
ThreadDemo1 t1 = new ThreadDemo1();
t1.setName("A线程");
//起动线程,进入就绪状态,等待cpu调度 (创建一条线程,得重新创建新的调用栈,内存分配等,过程是复杂的)
t1.start();
//main线程运行
for (int i = 0; i < 100; i++)
{
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
/**
* 当线程启动(进入就绪状态)以后,cpu调度此线程就会默认执行这个里面代码
*/
@Override
public void run()
{
for (int i = 0; i < 100; i++)
{
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class ThreadDemo2 implements Runnable
{
public static void main(String[] args)
{
//创建线程
ThreadDemo2 td1 = new ThreadDemo2();
//用实现Runnable线程创建的线程,还需要使用Thread包装一下才能起动
Thread t1 = new Thread(td1,"A线程");
t1.start();
//再创建一个
Thread t2 = new Thread(td1,"B线程");
t2.start();
//main
for (int i = 0; i < 100; i++)
{
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
@Override
public void run()
{
for (int i = 0; i < 100; i++)
{
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
使用退出标志,使线程正常退出,也就是当run方法完成后线程终止(常用)。
使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend,也可能发生不可预料的结果)。
使用interrupt方法中断线程。
- 使用退出标志
代码转载地址:https://blog.csdn.net/anhuidelinger/article/details/11746365
public class ThreadFlag extends Thread
{
public volatile boolean exit = false;
public void run()
{
while (!exit);
}
public static void main(String[] args) throws Exception
{
ThreadFlag thread = new ThreadFlag();
thread.start();
sleep(3000); // 主线程延迟3秒
thread.exit = true; // 终止线程thread
thread.join();
System.out.println("线程退出!");
}
}
- 使用stop方法终止线程
thread.stop();
- 使用interrupt方法终止线程
代码转载地址:https://blog.csdn.net/anhuidelinger/article/details/11746365
public class ThreadInterrupt extends Thread
{
public void run()
{
try
{
sleep(10000); // 延迟10秒
}
catch (InterruptedException e)
{
System.out.println(e.getMessage());
}
}
public static void main(String[] args) throws Exception
{
Thread thread = new ThreadInterrupt();
thread.start();
System.out.println("在10秒之内按任意键中断线程!");
System.in.read();
thread.interrupt();
thread.join();
System.out.println("线程已经退出!");
}
}
6.线程同步
多线程在竞争共享资源时,保证资源安全的一种手段。
synchronized、lock 实现同步
包裹的代码称之为临界区,每个对象都有并且仅有一把对象锁,只有拿到了锁的线程才能进入临界区,没有拿到锁的就在临界区外等待,这样就能保证同一时刻只有一个线程进入临界区。
主要相同点:Lock 能完成 synchronized 所实现的所有功能
主要不同点:Lock 有比 synchronized 更精确的线程语义和更好的性能。synchronized 会自动释放锁,而 Lock 一定要求程序员手工释放,并且必须在 finally 从句中释放。
线程异步:多线程可以同时对某个资源进行操作
-------------LOCK写法
public class LockTest {
private Lock lock = new ReentrantLock();
//需要参与同步的方法
private void method(Thread thread){
lock.lock();
try {
System.out.println("线程名"+thread.getName() + "获得了锁");
}catch(Exception e){
e.printStackTrace();
} finally {
System.out.println("线程名"+thread.getName() + "释放了锁");
lock.unlock();
}
}
}
-------------synchronized写法
第一种:
public void SynchronizedTestOne(){
synchronized(this){//加锁,this代表当前拿到锁的对象
System.out.println("SynchronizedTestOne");
Thread.sleep(1000);
System.out.println("线程名"+thread.getName() + "获得了锁");
}
}
第二种:
public synchronized void SynchronizedTestTwo() {
System.out.println("SynchronizedTestTwo");
try {
Thread.sleep(1000);
System.out.println("线程名"+thread.getName() + "获得了锁");
} catch (InterruptedException e) {
}
}
PS:AJAX是异步。Ajax(Asynchronous Javascript And XML) = 异步 JavaScript 和 XML(标准通用标记语言的子集)。
7.wait和sleep的区别
wait是Object中定义的方法,需要手工调用notify()或者notifyAll()方法;
wait表示当前线程在此对象上等待,wait的线程不会自动唤醒,必须由拿到同一个对象的锁的线程使用notify或notifyAll才会醒来;
wait时,线程会释放锁;
sleep是Thread类的一个静态方法,表示线程休眠,会自动唤醒;
sleep休眠指定时间后,会自动唤醒;
sleep时,线程不会释放锁;
sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。 wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
sleep就是正在执行的线程主动让出cpu,cpu去执行其他线程,在sleep指定的时间过后,cpu才会回到这个线程上继续往下执行,如果当前线程进入了同步锁,sleep方法并不会释放锁,即使当前线程使用sleep方法让出了cpu,但其他被同步锁挡住了的线程也无法得到执行。-----------意思就是在锁内调用sleep,当前线程睡眠之后继续运行,其他线程还是进不来
wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放。如果notify方法后面的代码还有很多,需要这些代码执行完后才会释放锁,可以在notfiy方法后增加一个等待和一些代码,看看效果),调用wait方法的线程就会解除wait状态和程序可以再次得到锁后继续向下运行。-----------在锁内调用此方法, 当前线程释放锁,其他线程能够去得到锁,能进入锁内。
线程池可以让我们重用现有的线程,减少线程创建,消亡的资源的开销,并且可以有效的控制最大的并发数量,避免过多的线程竞争。
创建一个可缓冲的线程池,如果当前的任务数量超过线程的数量,缓冲线程池会自动创建线程去处理任务,如果有线程长时间闲置,就会将其回收
ExecutorService executorSrv = Executors.newCachedThreadPool();
创建一个单线程池
ExecutorService executorSrv = Executors.newSingleThreadExecutor();
创建一个定长的线程池,线程池中的最大线程数量是5
ExecutorService executorSrv = Executors.newFixedThreadPool(5);
PS:现在还没怎么遇到线程池之类的问题,后面遇到了再完善此处… …