什么是线程 他和进程的区别
线程就是系统进行运算调度的最小单位 他包含在进程中 是进程的实际运行单位
线程是进程的子集 一个进程中有很多线程 线程则是共享进程的内存空间
1.进程是程序的一次执行
2.进程是一个程序及其数据在处理机上顺序执行时所发生的活动
3.进程是程序在一个数据集合上运行的过程,他是系统进行资源分配和调度的一个独立单位
线程的生命周期 创建 运行阻塞就绪 销毁
线程创建的三种方式
第一种 继承Thread类
public class MyThread extends Thread{//继承Thread类
public void run(){
//重写run方法
}
}
第二种 实现runnable接口 重写run方法
public class MyThread2 implements Runnable {//实现Runnable接口
public void run(){
//重写run方法
}
}
public class Main {
public static void main(String[] args){
//创建并启动线程
MyThread2 myThread=new MyThread2();
Thread thread=new Thread(myThread);
thread().start();
//或者 new Thread(new MyThread2()).start();
}
}
第三种 实现callable接口 实现call方法
public class CallableThreadTest implements Callable<Integer> {
public static void main(String[] args)
{
CallableThreadTest ctt = new CallableThreadTest();
FutureTask<Integer> ft = new FutureTask<>(ctt);
for(int i = 0;i < 100;i++)
{
System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);
if(i==20)
{
new Thread(ft,"有返回值的线程").start();
}
}
try
{
System.out.println("子线程的返回值:"+ft.get());
} catch (InterruptedException e)
{
e.printStackTrace();
} catch (ExecutionException e)
{
e.printStackTrace();
}
}
@Override
public Integer call() throws Exception
{
int i = 0;
for(;i<100;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
}
return i;
}
}
volatile变量指的是什么?
他是一个成员变量的修饰符 保证下一个读操作是在写操作之后发生
并发编程的三个概念
原子性 一些操作 要么全部执行 要么都不执行
可见性 指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值
有序性 :即程序执行的顺序按照代码的先后顺序执行。
一些规则
锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作
volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作
传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C
线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作
线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生
线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行
什么是线程安全
你代码所在的类有多个线程同时运行如果每次运行结果和单线程 运行结果一样 而且其他变量的值和预期的一样 那么说他就是线程安全的
如何去停止线程
正常情况下为run方法或call方法执行完之后线程就会终止
使用共享变量的方式
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("线程退出!");
}
}
使用interrupt
而是使用Thread提供的interrupt()方法,因为该方法虽然不会中断一个正在运行的线程,但是它可以使一个被阻塞的线程抛出一个中断异常,从而使线程提前结束阻塞状态,退出堵塞代码。
class MyThread extends Thread {
volatile boolean stop = false;
public void run() {
while (!stop) {
System.out.println(getName() + " is running");
try { sleep(1000); }
catch (InterruptedException e) {
System.out.println("week up from blcok...");
stop = true; // 在异常处理代码中修改共享变量的状态
}
}
System.out.println(getName() + " is exiting..."); } }
class InterruptThreadDemo3 {
public static void main(String[] args) throws InterruptedException {
MyThread m1 = new MyThread();
System.out.println("Starting thread...");
m1.start();
Thread.sleep(3000);
System.out.println("Interrupt thread...: " + m1.getName()); m1.stop = true; // 设置共享变量为true m1.interrupt(); // 阻塞时退出阻塞状态 Thread.sleep(3000); // 主线程休眠3秒以便观察线程m1的中断情况 System.out.println("Stopping application...");
}
}
**如何在两个线程间共享数据
1可以使用同一个对象
public class Ticket implements Runnable{
private int ticket = 10;
public void run() {
while(ticket>0){
ticket--;
System.out.println("当前票数为:"+ticket);
}
}
}
public class SellTicket {
/**
* @param args
*/
public static void main(String[] args) {
Ticket t = new Ticket();
new Thread(t).start();
new Thread(t).start();
}
}
2如果两个线程执行的代码不同 可以实现两个个对象 可以将共享数据分别传递给连个不同线程
3可以把这两个线程作为内部类 共享成员变量**
即把要共享的数据变得全局变量,这样就保证了操作的是同一份数据。同时内部类的方式使代码更加简洁。但是不如第一种解法条理那么清楚。
public class MyData {
private int j=0;
public synchronized void add(){
j++;
System.out.println("线程"+Thread.currentThread().getName()+"j为:"+j);
}
public synchronized void dec(){
j--;
System.out.println("线程"+Thread.currentThread().getName()+"j为:"+j);
}
public int getData(){
return j;
}
}
public class TestThread {
/**
* @param args
*/
public static void main(String[] args) {
final MyData data = new MyData();
for(int i=0;i<2;i++){
new Thread(new Runnable(){
public void run() {
data.add();
}
}).start();
new Thread(new Runnable(){
public void run() {
data.dec();
}
}).start();
}
}
}
wait和sleep的区别
sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
notify,notifyall,yield
notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。
notify他只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其他同样在等待被该对象notify的线程们,当第一个线程运行完毕以后释放对象上的锁,此时如果该对象没有再次使用notify语句,即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。
yield 线程让步 意思就是让自己或者其他线程运行
interrupt 设置中断标识为true 查询线程中断状态 并清零 中断状态 isinterpupt 是查询其他中断状态并不会改变中断标识