一、线程与进程的区别:
1.进程:
1)进程就是一个应用程序(虚拟机就是java在操作系统上的运行程序,就是java.exe);一个进程中可以包含一个或多个线程.
2)每个进程都有独立的代码和数据空间,进程的切换会有很大的开销
2.线程:
1)一个程序内部中的顺序控制流(左手画圆,右手画方是不是就是一种多线程呢?).
2)同一类线程共享代码和数据空间,每个线程有独立运行的栈和程序计数器,线程切换的开销小.
Java中分为main线程和主线程.(其实还有一个隐藏的线程,即垃圾回收线程)
3.线程的生命周期:
二、多线程实现的两种方式
1.继承Thread类
package test;
//1.继承Thread类
public class Thread1 extends Thread {
//2.重写run方法
@Override
public void run() {
for(int i=1;i<=50;i++) {
System.out.println("我是线程中的第"+i+"个i");
}
}
public static void main(String[] args) {
Thread1 thread1 = new Thread1();
//这里注意,开启线程使用默认方法start(),而不要写run()方法;
//3.执行start方法启动线程
thread1.start();
for(int i=1;i<=50;i++) {
System.out.println("我是main中的第"+i+"个i");
}
}
}
2.实现Runnable接口
package test;
public class RunAbleDemo implements Runnable {
private int count = 50;
//重写run方法
@Override
public void run() {
while(count>0) {
//Thread.currentThread()指当前运行中的线程
System.out.println("第"+count+"号已被"+Thread.currentThread().getName()+"售出");
count--;
}
}
public static void main(String[] args) {
RunAbleDemo runAbleDemo = new RunAbleDemo();
//传入实现Runnable接口的类的对象,以及线程名称????(不是很明白)
Thread t1 = new Thread(runAbleDemo,"线程1");
Thread t2 = new Thread(runAbleDemo,"线程2");
//设置优先级优先级越高,执行几率越大,并不是必定是优先级高的线程一定会第一个执行完.
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
}
}
接下来是我目前见到的一些方法的使用
1.Thread.sleep(long millis);
让线程中止一段时间,在睡眠期满的瞬间,再次调用该线程不一定会恢复他的执行
package test;
public class ThreadSleep extends Thread {
@Override
public void run() {
for(int i=1;i<=50;i++) {
System.out.println(i);
//此处的异常不能抛出,只能try-catch因为Thread没有抛出异常,所以这里也不行!
try {
//一般情况下单位都是毫秒,线程休眠1S(每1S执行一次??)
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadSleep sleep = new ThreadSleep();
sleep.start();
}
}
2.join();使当前线程等待,知道调用这个join方法的线程终止
AThread:
@Override
public void run() {
for(int i=1;i<=50;i++) {
System.out.println("我是第"+i+"个AThread");
}
}
BThread:
@Override
public void run() {
for(int i=1;i<=50;i++) {
System.out.println("我是第"+i+"个BThread");
}
}
MainThread:
package thread;
public class MainThread {
public static void main(String[] args) throws InterruptedException {
System.out.println("Main线程开始运行了!");
AThread aThread = new AThread();
BThread bThread = new BThread();
aThread.start();
bThread.start();
//记得异常是join()方法抛出的~~
aThread.join();
bThread.join();
System.out.println("Main线程结束运行了!");
}
}
三、线程同步
有时两个或多个线程可能会试图同时访问同一个资源,为了确保在任何时间点一个共享的资源只能被一个线程使用,就使用了同步这一概念.
同步代码块和同步方法代码:
package thread;
public class synchroThread implements Runnable {
private int count = 100;
@Override
public void run() {
while (count() > 0) {
// 同步代码块 this 指当前对象
synchronized (this) {
//这里处理了如果上一个线程在睡眠状态,导致没有count-- 下一个线程已经进来执行了,此时的count为1,所以会出现卖出第0号或负号
if (count > 0) {
System.out.println("第" + count + "号票已经被" + Thread.currentThread().getName() + "售出");
// 测试设置睡眠才能出现上述的那种错误
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
}
}
}
}
// 同步方法
public synchronized int count() {
return count;
}
public static void main(String[] args) {
synchroThread synchroThread = new synchroThread();
Thread t1 = new Thread(synchroThread, "窗口1");
Thread t2 = new Thread(synchroThread, "窗口2");
Thread t3 = new Thread(synchroThread, "窗口3");
Thread t4 = new Thread(synchroThread, "窗口4");
Thread t5 = new Thread(synchroThread, "窗口5");
Thread t6 = new Thread(synchroThread, "窗口6");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
注意事项:受到synchronized保护的程序代码块和方法中,要访问的对象属性必须设定为private,因为如果不设定为private,那么就可以用不同的方式来访问他,这样就达不到保护的作用了
synchronized方法
优点:
1)可以显示的知道哪些方法是被synchronized关键字保护的
缺点:
1)方法中有些内容是不需要同步的,如果该方法执行会花很长时间,那么其他人就要花较多的时间等待锁被归还
2)只能取得自己对象的锁,有时候程序设计的需求,可能会需要取得其他对象的锁.
synchronized代码块
优点:
1)可以针对某段程序代码同步,不需要浪费时间在别的程序代码上.
2)可以取得不同对象的锁
缺点:
1)无法显示的得知哪些方法是被synchronized关键字保护的.
四、死锁
1.两个线程,彼此在等待对方占据的锁
2.锁的归还几种方式:
- 基本上执行完同步的程序代码后,锁就会自动归还.
- 用break语句跳出同步的语句块,不过这对于写在方法声明的synchronized没有作用;
- 遇到return语句;
- 遇到了异常;
简易死锁代码:
DeadLockThread1:
package thread;
public class DeadLockThread1 extends Thread {
private Object locka;
private Object lockb;
public DeadLockThread1(Object locka, Object lockb) {
this.locka = locka;
this.lockb = lockb;
}
@Override
public void run() {
System.out.println("DeadLockThread1开始执行");
synchronized (locka) {
System.out.println("locka已被DeadLockThread1线程锁住");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (lockb) {
System.out.println("lockb已被DeadLockThread1线程锁住");
}
}
}
}
DeadLockThread2:
package thread;
public class DeadLockThread2 extends Thread {
private Object locka;
private Object lockb;
public DeadLockThread2(Object locka, Object lockb) {
this.locka = locka;
this.lockb = lockb;
}
@Override
public void run() {
System.out.println("DeadLockThread2开始执行");
synchronized (lockb) {
System.out.println("lockb已被DeadLockThread2线程锁住");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (locka) {
System.out.println("locka已被DeadLockThread2线程锁住");
}
}
}
}
测试一下死锁程序:
DeadLockTest:
package thread;
public class DeadLockTest {
static Object locka = new Object();
static Object lockb = new Object();
public static void main(String[] args) {
DeadLockThread1 dThread1 = new DeadLockThread1(locka, lockb);
DeadLockThread2 dThread2 = new DeadLockThread2(locka, lockb);
dThread1.start();
dThread2.start();
}
}
我还是一个刚刚入门的萌新,
这篇文章也只是我用来记录自己学习过程的第一步…如果有什么不对的地方还请前辈,大佬们指出,让我提前改正,万分感谢.