今天学习了Java中的多线程机制,顺便查了下Java里的类的重要概念。
类是看别人的code
类:Java中的类也是一种构造数据类型,但是对C语言中的结构体有所升级,进行了一些扩展,类的成员不但可以是变量,还可以是函数(方法),通过类定义出来的变量也有特定的称,叫做“对象”
public class Demo {
public static void main(String[] args){
// 定义类Student
class Student{ // 通过class关键字类定义类
// 类包含的变量
String name;
int age;
float score;
// 类包含的函数
void say(){
System.out.println( name + "的年龄是 " + age + ",成绩是 " + score );
}
}
// 通过类来定义变量,即创建对象
Student stu1 = new Student(); // 必须使用new关键字
// 操作类的成员
stu1.name = "小明";
stu1.age = 15;
stu1.score = 92.5f;
stu1.say();
}
}
线程是自己学习的:
package zhongduan;
//类
public class TwoThreads_Test {
//主方法,用start方法启动线程
public static void main(String[] args) {
new Thread_Test("线程 1").start();
new Thread_Test("线程 2").start();
}
}
//重写类
class Thread_Test extends Thread{
public Thread_Test(String str){
super(str);
}
//写类中的run方法,每个线程循环十次,等于在抢占执行权,遇到另一个要使用时等待
public void run(){
for(int i = 0; i < 10; i++){
System.out.println(i+""+getName());
try{
sleep((int)(Math.random()*1000));
}catch(InterruptedException e){
}
}
System.out.println("执行结束!"+getName());
}
}
结果:
0线程 2
0线程 1
1线程 2
2线程 2
1线程 1
2线程 1
3线程 2
3线程 1
4线程 2
4线程 1
5线程 1
6线程 1
5线程 2
7线程 1
8线程 1
6线程 2
7线程 2
9线程 1
执行结束!线程 1
8线程 2
9线程 2
执行结束!线程 2
有点意思。。。
用Runnable接口实现多线程,一个小程序实现一秒刷新一次当前时间:
package zhongduan;
import java.applet.Applet;
import java.awt.Graphics;
import java.util.Date;
public class Runnable_Test extends Applet implements Runnable {//实现Runnable接口
Thread thread; //建立类的对象
public void start(){
if(thread == null){
//线程体是Clock对象本身,线程名字是“Clock”
thread = new Thread(this, "小时钟");
thread.start(); //启动线程用start
}
}
public void run(){ //run方法中是线程执行的内容,是必须要写的
while(thread != null){
repaint(); //获取当前时间
try{ //睡眠一秒,每隔一秒执行一次
Thread.sleep(1000);
}catch(InterruptedException e){
}
}
}
public void paint(Graphics g){
Date now = new Date(); //创建当前时间对象
g.drawString(now.getHours() + ":" + now.getMinutes() + ":"
+ now.getSeconds(),5 ,10); //显示当前时间
}
public void stop(){
thread.stop();
thread = null;
}
}
结果:
Thread类:
- 不能再从其他类继承,无需使用Thread.currentThread()
- 可以直接操纵线程
Runnable接口:
- 可从其他类继承
线程调度
Java系统中,线程调度在优先级的基础上服从“先到先服务”原则。
当一个在就绪队列中排队的线程被分配到处理器资源而进入运行状态时,这个线程就被称为是被调度或被线程调度管理器选中。
下面几种情况下,当前线程会放弃CPU:
- 线程调用了yield()或sleep()方法
- 抢先式系统下,由高优先级的线程参与调度;时间片方式下,当前时间片用完,由同优先级的线程参与调度
- 当前线程进行I/O访问、外存读写、等待用户输入等操作,导致线程阻塞;或者是为等候一个条件变量,以及线程调用wait()方法。
Thread类的setPriority(int a)方法可以设置线程优先级
a取值可以是Thread.MIN_PRIORITY
MIN也可以是MAX和NORM,系统默认NORM
下面是三个线程,其中两个有高优先级:
package zhongduan;
public class ThreadPriority_Test {
public static void main(String[] args) {
Thread thread1 = new MyThread("Thread1");
thread1.setPriority(Thread.MIN_PRIORITY);//优先级最小
thread1.start();
Thread thread2 = new MyThread("Thread2");
thread1.setPriority(Thread.MAX_PRIORITY);//优先级最大
thread2.start();
Thread thread3 = new MyThread("Thread3");
thread1.setPriority(Thread.MAX_PRIORITY);//优先级最大
thread3.start();
}
}
class MyThread extends Thread{ //对MyYhread类描写
String msg;
public MyThread(String msg) { //类重构
super();
this.msg = msg;
}
public void run(){ //run方法表示执行几次,必须写
for(int i = 0;i < 3;i ++)
System.out.println(msg+""+getPriority());
}
}
结果:
Thread110
Thread25
Thread25
Thread25
Thread35
Thread110
Thread35
Thread35
Thread110
join()方法:
当前线程等待调用该方法的线程结束后,再恢复执行
下面是简化的Account类,Mike账户上原本有2000元,首先生成1000个线程,每个线程都对账户存100又马上取出100元,不对deposit和withdraw方法加synchronized,当前线程的动作会被其他进程覆盖,有时得不到2000元:
package zhongduan;
public class Synchronized_Test {
private static int NUM_OF_THREAD = 1000;
static Thread[] threads = new Thread[NUM_OF_THREAD];
public static void main(String[] args) {
final Account acc = new Account("Mike",2000.0f);
for(int i = 0 ; i< NUM_OF_THREAD; i++){
threads[i] = new Thread(new Runnable(){
public void run(){
acc.deposit(100.0f);
acc.withdraw(100.0f);
}
});
threads[i].start();
}
for(int i = 0; i < NUM_OF_THREAD;i++){
try{
threads[i].join(); //等待所有线程运行结束
}catch(InterruptedException e){
}
}
System.out.println("最终,Mike的卡上还剩下:"+acc.getBalance());
}
}
class Account{
String name;
float amount;
public Account(String name, float amount) {
super();
this.name = name;
this.amount = amount;
}
public synchronized void deposit(float amt){
float tmp = amount;
tmp += amt;
try{
Thread.sleep(100); //模拟其他处理,比如刷新数据库
}catch(InterruptedException e){
}
amount = tmp;
}
public synchronized void withdraw(float amt){
float tmp = amount;
tmp = tmp - amt;
try{
Thread.sleep(100); //模拟其他处理,比如刷新数据库
}catch(InterruptedException e){
}
amount = tmp;
}
public float getBalance(){
return amount;
}
}