1. 线程
2. 用Thread类创建线程:继承Thread类后重写run方法,在主函数中创建出该类后调用start方法启动线程
publicclass ThreadDemo1 {
publicstaticvoid main(String[] args) {
new TestThread().start();
while(true){
System.out.println("main():" + Thread.currentThread().getName());//打印出当前线程类的名称
}
}
}
class TestThread extends Thread{
publicvoid run(){
while(true){
System.out.println("run():" + Thread.currentThread().getName());
}
}
}
3. 前台线程和后台线程:如果是前台线程比如上面的TestThread,则main主线程结束的时候,TestThread线程仍然在执行;如果是后台线程,则前台线程结束后,后台线程也会结束;如下:
publicclass ThreadDemo1 {
publicstaticvoid main(String[] args) {
// new TestThread().start();
Thread aa = new TestThread();
aa.setDaemon(true);
aa.start();
/*while(true){
System.out.println("main():"+ Thread.currentThread().getName());//打印出当前线程类的名称
}*/
}
}
class TestThread extends Thread{
publicvoid run(){
while(true){
System.out.println("run():" + Thread.currentThread().getName());
}
}
}
4. 联合线程:
publicclass ThreadDemo1 {
publicstaticvoid main(String[] args) {
// new TestThread().start();
Thread aa = new TestThread();
// aa.setDaemon(true);
aa.start();
int index = 0;
while (true) {
if (index++ == 200){
try {
aa.join();// 将aa线程合并到主线程中,之后aa线程在执行,主线程在等待;也可以在join方法中指定合并线程的时间
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
System.out.println("main():" + Thread.currentThread().getName());// 打印出当前线程类的名称
}
}
}
class TestThread extends Thread {
publicvoid run() {
while (true) {
System.out.println("run():" + Thread.currentThread().getName());
}
}
}
5. 利用runnable接口实现Thread
public class ThreadDemo1 {
public static void main(String[] args) {
// new TestThread().start();
Thread aa = new Thread(newTestThread());
// aa.setDaemon(true);
aa.start();
int index = 0;
while (true) {
if (index++ == 200){
try {
aa.join(1000);// 将aa线程合并到主线程中,之后aa线程在执行,主线程在等待;也可以在join方法中指定合并线程的时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("main():" + Thread.currentThread().getName());// 打印出当前线程类的名称
}
}
}
class TestThread implements Runnable {
publicvoid run() {
while (true) {
System.out.println("run():" + Thread.currentThread().getName());
}
}
}
6. 使用runnable接口实现的线程比继承Thread类实现的线程灵活得多:
public class ThreadDemo1 {
public static void main(String[] args) {
// new TestThread().start();
Thread aa = new TestThread();
// aa.setDaemon(true);
aa.start();
aa.start();
aa.start();
}
}
class TestThread extends Thread {
int tickets = 100;
public void run() {
while (true) {
if(tickets > 0)
System.out.println("run():" + Thread.currentThread().getName()
+ "is saling ticket" + tickets--);
}
}
}
上面的代码中只是启动了一个线程;
public class ThreadDemo1 {
public static void main(String[] args) {
// new TestThread().start();
TestThread aa = new TestThread();
// aa.setDaemon(true);
new Thread(aa).start();
new Thread(aa).start();
new Thread(aa).start();
new Thread(aa).start();
}
}
class TestThreadimplements Runnable {
inttickets = 100;
publicvoid run() {
while (true) {
if(tickets > 0)
System.out.println("run():" + Thread.currentThread().getName()
+ "is saling ticket" + tickets--);
}
}
}
7. 使用runnable接口可以实现几块代码同时处理相同的资源,所以这种用法使用比较多;
8. 多线程的应用:网络聊天程序,将发信息和接受信息放置到两个线程中执行;
9. 多线程的同步问题:问题的出现
public class ThreadDemo1 {
public static void main(String[] args) {
// new TestThread().start();
TestThread aa = new TestThread();
// aa.setDaemon(true);
new Thread(aa).start();
new Thread(aa).start();
new Thread(aa).start();
new Thread(aa).start();
}
}
class TestThreadimplements Runnable {
inttickets = 100;
publicvoid run() {
while (true) {
if(tickets > 0){
try {
Thread.sleep(10);
} catch (InterruptedExceptione) {
//TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("run():" + Thread.currentThread().getName()
+ "is saling ticket" + tickets--);
}
}
}
}
通过睡眠10毛秒就会发生线程的同步问题,这样就会出现卖通一张票的问题;同步问题就是解决代码的原子性问题;
10.同步问题的解决:通过同步语句块实现(synchronized)
public class ThreadDemo1 {
public static void main(String[] args) {
// new TestThread().start();
TestThread aa = new TestThread();
// aa.setDaemon(true);
new Thread(aa).start();
new Thread(aa).start();
new Thread(aa).start();
new Thread(aa).start();
}
}
class TestThreadimplements Runnable {
inttickets = 100;
String str = new String("");
publicvoid run() {
while (true) {
synchronized (str) {
if(tickets > 0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("run():" + Thread.currentThread().getName()
+ "is saling ticket" + tickets--);
}
}
}
}
}
通过对象的标志位进行标识,使当前的同步代码块在同一时刻只能被一个线程调用;注意同步代码块的实现是使用监视器对象实现的,所以监视器对象的创建不能在run方法中,否则不同的线程就会拥有自己的监视器对象无法达到同步的目的;
11.通过同步方法实现:将可能发生同步问题的代码抽取到同步方法中实现
public class ThreadDemo1 {
public static void main(String[] args) {
// new TestThread().start();
TestThread aa = new TestThread();
// aa.setDaemon(true);
new Thread(aa).start();
new Thread(aa).start();
new Thread(aa).start();
new Thread(aa).start();
}
}
class TestThreadimplements Runnable {
inttickets = 100;
publicvoid run() {
while (true) {
sale();
}
}
privatesynchronizedvoid sale() {
if (tickets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("run():" + Thread.currentThread().getName()
+ "is saling ticket" + tickets--);
}
}
}
12.同步代码块影响程序的执行效率
13.线程start之后只是说明当前的线程处于启动状态,不一定立即执行;代码的顺序不一定是线程启动的顺序;
14.验证同步方法所使用的监视器对象是this,实现代码块和方法的同步;
public class ThreadDemo1 {
public static void main(String[] args) {
// new TestThread().start();
TestThread aa = new TestThread();
// aa.setDaemon(true);
new Thread(aa).start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catchblock
e.printStackTrace();
}
aa.str = "method";
new Thread(aa).start();
new Thread(aa).start();
new Thread(aa).start();
}
}
class TestThreadimplements Runnable {
inttickets = 100;
String str = new String("");
publicvoid run() {
if (str.equals("method")) {
while(true){
sale();
}
} else {
while (true) {
synchronized (this) {
if (tickets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("run():"
+ Thread.currentThread().getName()
+ "is saling ticket" + tickets--);
}
}
}
}
}
privatesynchronizedvoid sale() {
if (tickets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
System.out.print("sale ");
System.out.println("run():" + Thread.currentThread().getName()
+ "is saling ticket" + tickets--);
}
}
}
15.线程的死锁问题
public class ThreadDemo1 {
public static void main(String[] args) {
// new TestThread().start();
TestThread aa = new TestThread();
// aa.setDaemon(true);
new Thread(aa).start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
aa.str ="method";
new Thread(aa).start();
new Thread(aa).start();
new Thread(aa).start();
}
}
class TestThreadimplements Runnable {
inttickets = 100;
String str = new String("");
publicvoid run() {
if (str.equals("method")) {
while(true){
sale();
}
} else {
while (true) {
synchronized (str) {
if (tickets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (this) {
}
System.out.println("run():"
+ Thread.currentThread().getName()
+ "is saling ticket" + tickets--);
}
}
}
}
}
privatesynchronizedvoid sale() {
if (tickets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (str) {
}
System.out.print("sale ");
System.out.println("run():" + Thread.currentThread().getName()
+ "is saling ticket" + tickets--);
}
}
}
16.线程间的通信:生产者和消费者之间的关系,生产者生产一个产品消费者才能消费一个产品;
class Producer implements Runnable {
Q q;
public Producer(Q q) {
this.q = q;
}
@Override
publicvoid run() {
int i = 0;
while (true) {
synchronized (q) {
if(q.bFull){
try {
q.wait();
} catch(InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
if (i == 0) {
q.name ="zhangsan";
try {
Thread.sleep(1);
} catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
q.sex ="male";
} else {
q.name ="lisi";
q.sex ="female";
}
i = (i + 1) % 2;
q.bFull =true;
q.notify();
}
}
}
}
class Consumerimplements Runnable {
Q q;
public Consumer(Q q) {
this.q = q;
}
@Override
publicvoid run() {
while (true) {
synchronized (q) {
if(!q.bFull){
try {
q.wait();
} catch(InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
System.out.print(q.name);
System.out.println(" : " +q.sex);
q.bFull =false;
q.notify();
}
}
}
}
class Q {
String name;
String sex;
Boolean bFull =false;
}
publicclass ThreadCommunation {
publicstaticvoid main(String[] args) {
Q q = new Q();
new Thread(new Producer(q)).start();
new Thread(new Consumer(q)).start();
}
}
以上的代码中将q作为共同的监视器,解决了同步问题;为了解决线程多次访问同一个资源使用了线程间的通信;通过q.wait()方法将当前的线程置入等待状态,释放cpu的使用权;使用q.notify()方法通知其他线程启动;
将以上代码进行优化后的代码:
class Producer implements Runnable {
Q q;
public Producer(Q q) {
this.q = q;
}
@Override
publicvoid run() {
int i = 0;
while (true) {
synchronized (q) {
if (i == 0) {
q.put("zhangsan","male");
} else {
q.put("lisi","female");
}
i = (i + 1) % 2;
}
}
}
}
class Consumerimplements Runnable {
Q q;
public Consumer(Q q) {
this.q = q;
}
@Override
publicvoid run() {
while (true) {
synchronized (q) {
q.get();
}
}
}
}
class Q {
private Stringname;
private Stringsex;
private BooleanbFull = false;
public synchronized voidput(String name, String sex) {
if (bFull) {
try {
wait();
} catch (InterruptedException e){
// TODO Auto-generated catchblock
e.printStackTrace();
}
}
this.name = name;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catchblock
e.printStackTrace();
}
this.sex = sex;
bFull = true;
notify();
}
public synchronized voidget() {
if (!bFull) {
try {
wait();
} catch (InterruptedException e){
// TODO Auto-generated catchblock
e.printStackTrace();
}
}
System.out.print(name);
System.out.println(" : "+ sex);
bFull = false;
notify();
}
}
publicclass ThreadCommunation {
publicstaticvoid main(String[] args) {
Q q = new Q();
new Thread(new Producer(q)).start();
new Thread(new Consumer(q)).start();
}
}
上面的代码是将对Q类的处理都抽象为自己的方法,同时这些方法都是线程安全的,更加符合面向对象的思想;