java多線程數據
可以用拍孝櫻Scoket套接字讓伺服器和慎畝客戶端襲叢建立連接
可以根據Scoket對象的getInputStream()和getOutputStream()獲得輸入輸出流
再往流裡面寫信息
就實現了簡單的數據傳遞
當然等待數據
的時候會有阻塞現象
所以使用線程來保證數據不會因為等待而阻塞
以mysql為資料庫寫的一個粗陋的demo,你參考一下,希望不會因為代碼過多被網路吞了——
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
allotThread();
}
/**
* 將100條數據分成10份並啟動10個線程分別操作
*/
public static void allotThread() {
List<String[]> datas = buildDatas();
for (int i=0; i<100; i+=10) {
List<String[]> tenDatas = datas.subList(i, i + 10);
insertData(tenDatas);
}
}
/**
* 創建100條模擬數據
* @return
*/
public static List<String[]> buildDatas() {
List<String[]> datas = new ArrayList<String[]>();
for (int i=0; i<100; i++) {
String[] data = {"id " + i, "name " + i};
datas.add(data);
}
return datas;
}
/**
* 啟動線程進行數據插入操作
* @param tenDatas
*/
public static void insertData(final List<String[]> tenDatas) {
new Thread(new Runnable() {
public void run() {
String sql = "insert into testtable (id, name) values (?, ?)";
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = getConnection();
conn.setAutoCommit(false);
pstmt = getPstmt(conn, sql);
for (String[] data : tenDatas) {
pstmt.setString(1, data[0]);
pstmt.setString(2, data[1]);
pstmt.addBatch();
}
pstmt.executeBatch();
conn.commit();
conn.setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
rollback(conn);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
close(pstmt);
close(conn);
}
}
}).start();
}
public static Connection getConnection() throws SQLException, ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
String dbUrl = "jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=UTF-8";
Connection conn = DriverManager.getConnection(dbUrl, "root", "tooeasy");
return conn;
}
public static PreparedStatement getPstmt(Connection conn, String sql) throws SQLException, ClassNotFoundException {
PreparedStatement pstmt = conn.prepareStatement(sql);
return pstmt;
}
public static void rollback(Connection conn) {
try {
if (null != conn) {
conn.rollback();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void close(Connection conn) {
try {
if (null != conn) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void close(PreparedStatement pstmt) {
try {
if (null != pstmt) {
pstmt.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void close(ResultSet rs) {
try {
if (null != rs) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Ⅲ java 多線程操作資料庫
//將資料庫中的數據條數分段
publicvoiddivision(){
//獲取要導入的總的數據條數
Stringsql3="SELECTcount(*)FROM[CMD].[dbo].[my1]";
try{
pss=cons.prepareStatement(sql3);
rss=pss.executeQuery();
while(rss.next()){
System.out.println("總記錄條數:"+rss.getInt(1));
sum=rss.getInt(1);
}
//每30000條記錄作為一個分割點
if(sum>=30000){
n=sum/30000;
resie=sum%30000;
}else{
resie=sum;
}
System.out.println(n+""+resie);
}catch(SQLExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
線程類
publicMyThread(intstart,intend){
this.end=end;
this.start=start;
System.out.println("處理掉余數");
try{
System.out.println("--------"+Thread.currentThread().getName()+"------------");
Class.forName(SQLSERVERDRIVER);
System.out.println("載入sqlserver驅動...");
cons=DriverManager.getConnection(CONTENTS,UNS,UPS);
stas=cons.createStatement();
System.out.println("連接SQLServer資料庫成功!!");
System.out.println("載入mysql驅動.....");
Class.forName(MYSQLDRIVER);
con=DriverManager.getConnection(CONTENT,UN,UP);
sta=con.createStatement();
//關閉事務自動提交
con.setAutoCommit(false);
System.out.println("連接mysql資料庫成功!!");
}catch(Exceptione){
e.printStackTrace();
}
//TODOAuto-generatedconstructorstub
}
publicArrayList<Member>getAll(){
Membermember;
Stringsql1="select*from(selectrow_number()over(orderbypmcode)asrowNum,*"+
"from[CMD].[dbo].[my1])astwhererowNumbetween"+start+"and"+end;
try{
System.out.println("正在獲取數據...");
allmembers=newArrayList();
rss=stas.executeQuery(sql1);
while(rss.next()){
member=newMember();
member.setAddress1(rss.getString("address1"));
member.setBnpoints(rss.getString("bnpoints"));
member.setDbno(rss.getString("dbno"));
member.setExpiry(rss.getString("expiry"));
member.setHispoints(rss.getString("hispoints"));
member.setKypoints(rss.getString("kypoints"));
member.setLevels(rss.getString("levels"));
member.setNames(rss.getString("names"));
member.setPmcode(rss.getString("pmcode"));
member.setRemark(rss.getString("remark"));
member.setSex(rss.getString("sex"));
member.setTelephone(rss.getString("telephone"));
member.setWxno(rss.getString("wxno"));
member.setPmdate(rss.getString("pmdate"));
allmembers.add(member);
//System.out.println(member.getNames());
}
System.out.println("成功獲取sqlserver資料庫數據!");
returnallmembers;
}catch(SQLExceptione){
//TODOAuto-generatedcatchblock
System.out.println("獲取sqlserver資料庫數據發送異常!");
e.printStackTrace();
}
try{
rss.close();
stas.close();
}catch(SQLExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
returnnull;
}
publicvoidinputAll(ArrayList<Member>allmembers){
System.out.println("開始向mysql中寫入");
Stringsql2="insertintotest.my2values(?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
try{
ps=con.prepareStatement(sql2);
System.out.println("-------------------------等待寫入數據條數:"+allmembers.size());
for(inti=0;i<allmembers.size();i++){
ps.setString(1,allmembers.get(i).getPmcode());
ps.setString(2,allmembers.get(i).getNames());
//System.out.println(allmembers.get(i).getNames());
ps.setString(3,allmembers.get(i).getSex());
ps.setString(4,allmembers.get(i).getTelephone());
ps.setString(5,allmembers.get(i).getAddress1());
ps.setString(6,allmembers.get(i).getPmdate());
ps.setString(7,allmembers.get(i).getExpiry());
ps.setString(8,allmembers.get(i).getLevels());
ps.setString(9,allmembers.get(i).getDbno());
ps.setString(10,allmembers.get(i).getHispoints());
ps.setString(11,allmembers.get(i).getBnpoints());
ps.setString(12,allmembers.get(i).getKypoints());
ps.setString(13,allmembers.get(i).getWxno());
ps.setString(14,allmembers.get(i).getRemark());
//插入命令列表
//ps.addBatch();
ps.executeUpdate();
}
//ps.executeBatch();
con.commit();
ps.close();
con.close();
this.flag=false;
System.out.println(Thread.currentThread().getName()+"--->OK");
}catch(SQLExceptione){
//TODOAuto-generatedcatchblock
System.out.println("向mysql中更新數據時發生異常!");
e.printStackTrace();
}
}
@Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
while(true&&flag){
this.inputAll(getAll());
}
}
Ⅳ Java多線程程序設計初步入門
在Java語言產生前 傳統的程序設計語言的程序同一時刻只能單任務操作 效率非常低 例如程序往往在接收數據輸入時發生阻塞 只有等到程序獲得數據後才能繼續運行 隨著Internet的迅猛發展 這種狀況越來越不能讓人們忍受 如果網路接收數據阻塞 後台程序就處於等待狀態而不繼續任何操作 而這種阻塞是經常會碰到的 此時CPU資源被白白的閑置起來 如果在後台程序中能夠同時處理多個任務 該多好啊!應Internet技術而生的Java語言解決了這個問題 多線程程序是Java語言的一個很重要的特點 在一個Java程序中 我們可以同時並行運行多個相對獨立的線程 例如 我們如果創建一個線程來進行數據輸入輸出 而創建另一個線程在後台進行其它的數據處理 如果輸入輸出線程在接收數據時阻塞 而處理數據的線程仍然在運行 多線程程序設計大大提高了程序執行效率和處理能力
線程的創建
我們知道Java是面向對象的程序語言 用Java進行程序設計就是設計和使用類 Java為我們提供了線程類Thread來創建線程 創建線程與創建普通鬧梁的類的對象的操作是一樣的 而線程就是Thread類或其子類的實例對象 下面是一個創建啟動一個線程的語句
Thread thread =new Thread(); file://聲明困彎神一個對象實例 即創建一個線程
Thread run(); file://用Thread類中的run()方法啟動線程
從這個例子 我們可以通過Thread()構造方法創建一個線程 並啟動該線程 事實上 啟動線程 也就是啟動線程的run()方法 而Thread類中的run()方法沒有任何操作語句 所以這個線程沒有任何操作 要使線程實現預定功能 必須定義自己的run()方法 Java中通常有兩種方式定義run()方法
通過定義一個Thread類的子類 在該子類中重寫run()方法 Thread子類的實例對象就是一個線程 顯然 該線程汪虧有我們自己設計的線程體run()方法 啟動線程就啟動了子類中重寫的run()方法
通過Runnable介面 在該介面中定義run()方法的介面 所謂介面跟類非常類似 主要用來實現特殊功能 如復雜關系的多重繼承功能 在此 我們定義一個實現Runnable() 介面的類 在該類中定義自己的run()方法 然後以該類的實例對象為參數調用Thread類的構造方法來創建一個線程
線程被實際創建後處於待命狀態 激活(啟動)線程就是啟動線程的run()方法 這是通過調用線程的start()方法來實現的
下面一個例子實踐了如何通過上述兩種方法創建線程並啟動它們
// 通過Thread類的子類創建的線程 class thread extends Thread { file://自定義線程的run()方法 public void run() { System out println( Thread is running… ); } } file://通過Runnable介面創建的另外一個線程 class thread implements Runnable { file://自定義線程的run()方法 public void run() { System out println( Thread is running… ); } } file://程序的主類 class Multi_Thread file://聲明主類 { plubic static void mail(String args[]) file://聲明主方法 { thread threadone=new thread (); file://用Thread類的子類創建線程 Thread threado=new Thread(new thread ()); file://用Runnable介面類的對象創建線程 threadone start(); threado start(); file://strat()方法啟動線程 } }
運行該程序就可以看出 線程threadone和threado交替佔用CPU 處於並行運行狀態 可以看出 啟動線程的run()方法是通過調用線程的start()方法來實現的(見上例中主類) 調用start()方法啟動線程的run()方法不同於一般的調用方法 調用一般方法時 必須等到一般方法執行完畢才能夠返回start()方法 而啟動線程的run()方法後 start()告訴系統該線程准備就緒可以啟動run()方法後 就返回start()方法執行調用start()方法語句下面的語句 這時run()方法可能還在運行 這樣 線程的啟動和運行並行進行 實現了多任務操作
線程的優先順序
對於多線程程序 每個線程的重要程度是不盡相同 如多個線程在等待獲得CPU時間時 往往我們需要優先順序高的線程優先搶佔到CPU時間得以執行 又如多個線程交替執行時 優先順序決定了級別高的線程得到CPU的次數多一些且時間多長一些 這樣 高優先順序的線程處理的任務效率就高一些
Java中線程的優先順序從低到高以整數 ~ 表示 共分為 級 設置優先順序是通過調用線程對象的setPriority()方法 如上例中 設置優先順序的語句為
thread threadone=new thread (); file://用Thread類的子類創建線程
Thread threado=new Thread(new thread ()); file://用Runnable介面類的對象創建線程
threadone setPriority( ); file://設置threadone的優先順序
threado setPriority( ); file://設置threado的優先順序
threadone start(); threado start(); file://strat()方法啟動線程
這樣 線程threadone將會優先於線程threado執行 並將佔有更多的CPU時間 該例中 優先順序設置放在線程啟動前 也可以在啟動後進行設置 以滿足不同的優先順序需求
線程的(同步)控制
一個Java程序的多線程之間可以共享數據 當線程以非同步方式訪問共享數據時 有時候是不安全的或者不和邏輯的 比如 同一時刻一個線程在讀取數據 另外一個線程在處理數據 當處理數據的線程沒有等到讀取數據的線程讀取完畢就去處理數據 必然得到錯誤的處理結果 這和我們前面提到的讀取數據和處理數據並行多任務並不矛盾 這兒指的是處理數據的線程不能處理當前還沒有讀取結束的數據 但是可以處理其它的數據
如果我們採用多線程同步控制機制 等到第一個線程讀取完數據 第二個線程才能處理該數據 就會避免錯誤 可見 線程同步是多線程編程的一個相當重要的技術
在講線程的同步控制前我們需要交代如下概念
用Java關鍵字synchonized同步對共享數據操作的方法
在一個對象中 用synchonized聲明的方法為同步方法 Java中有一個同步模型 監視器 負責管理線程對對象中的同步方法的訪問 它的原理是 賦予該對象唯一一把 鑰匙 當多個線程進入對象 只有取得該對象鑰匙的線程才可以訪問同步方法 其它線程在該對象中等待 直到該線程用wait()方法放棄這把鑰匙 其它等待的線程搶占該鑰匙 搶佔到鑰匙的線程後才可得以執行 而沒有取得鑰匙的線程仍被阻塞在該對象中等待
file://聲明同步的一種方式 將方法聲明同步
class store {public synchonized void store_in(){… }public synchonized void store_out(){ … }}
利用wait() notify()及notifyAll()方法發送消息實現線程間的相互聯系
Java程序中多個線程通過消息來實現互動聯系的 這幾種方法實現了線程間的消息發送 例如定義一個對象的synchonized 方法 同一時刻只能夠有一個線程訪問該對象中的同步方法 其它線程被阻塞 通常可以用notify()或notifyAll()方法喚醒其它一個或所有線程 而使用wait()方法來使該線程處於阻塞狀態 等待其它的線程用notify()喚醒
一個實際的例子就是生產和銷售 生產單元將產品生產出來放在倉庫中 銷售單元則從倉庫中提走產品 在這個過程中 銷售單元必須在倉庫中有產品時才能提貨 如果倉庫中沒有產品 則銷售單元必須等待
程序中 假如我們定義一個倉庫類store 該類的實例對象就相當於倉庫 在store類中定義兩個成員方法 store_in() 用來模擬產品製造者往倉庫中添加產品 strore_out()方法則用來模擬銷售者從倉庫中取走產品 然後定義兩個線程類 customer類 其中的run()方法通過調用倉庫類中的store_out()從倉庫中取走產品 模擬銷售者 另外一個線程類procer中的run()方法通過調用倉庫類中的store_in()方法向倉庫添加產品 模擬產品製造者 在主類中創建並啟動線程 實現向倉庫中添加產品或取走產品
如果倉庫類中的store_in() 和store_out()方法不聲明同步 這就是個一般的多線程 我們知道 一個程序中的多線程是交替執行的 運行也是無序的 這樣 就可能存在這樣的問題
倉庫中沒有產品了 銷售者還在不斷光顧 而且還不停的在 取 產品 這在現實中是不可思義的 在程序中就表現為負值 如果將倉庫類中的stroe_in()和store_out()方法聲明同步 如上例所示 就控制了同一時刻只能有一個線程訪問倉庫對象中的同步方法 即一個生產類線程訪問被聲明為同步的store_in()方法時 其它線程將不能夠訪問對象中的store_out()同步方法 當然也不能訪問store_in()方法 必須等到該線程調用wait()方法放棄鑰匙 其它線程才有機會訪問同步方法
lishixin/Article/program/Java/gj/201311/27301
Ⅳ java多線程操作資料庫
首先,你的確定數據的主鍵是否可以返配使用序列自增。
如果可以那麼你可以在插入數察純據的時候獲取序列里的值,這樣數據就不會重復了。
其次,可以創建一個公共方漏沒指法,進行數據的插入操作,並且方法類型聲明為 static synchronized
類型,這樣基本上就不會出現數據重復的現象了
最後,要看你是怎麼獲得待插入源數據了,這個獲得數據源的方法也做成static synchronized的公
共方法。
Ⅵ 如何證明Java多線程中的成員變數數據是互不可見的
Java多線程裡面有一個數據不可見的問題而我們知道使用volatile可以解決,但是如何證明這個多線程修改共享數據是不可見的呢?
很簡單,看下面的一段代碼:碰搜
private static boolean keepRunning=true;
public static void main(String[] args) throws Exception {
new Thread(
()->{
while (keepRunning){
//System.out.println();
}
}
).start();
Thread.sleep(1000);
keepRunning=false;
}
上面的代碼是笑逗歷在JDK8的環境下運行的,我們看到有一個靜態的boolean變數的值是true,然後在main方法中我們聲明又創建指攜了一個新的線程,並使用lambda語法創建了一個循環,接著在線程啟動後我們在主線程的最後一行里把boolean變數的值給改變了。
如果兩個線程的數據是可見的,那麼上面的程序是會自動終止的,如果不可見則會進入一個無限循環中。
我分別在windows系統和mac系統運行上面的程序,結果都是死循環,程序永遠不會停止,這也證明了我們上面的結論,然後如果把 keepRunning 變數加上volatile修飾後,程序是可以終止的,這也正是volatile關鍵字的作用,可以使得多個線程之間的共享數據在修改後,對其他的線程立即可見。
Ⅶ Java如何處理多線程的數據同步問題
通過synchronize加鎖進行喊宏實謹滲差現進行之間的互斥、通過wait、notify方法實現線程之間的同步。祥皮
Ⅷ java語言支持多線程它能同步共享數據處理不同的事件對嗎
對。根據博客官網相關緩搜查詢得知,java語言支持多線程是能同步共享數據處理不同的事件的。Java,是型喊一門面向對象編程語言,1990年代初由詹姆斯·高斯林等人開發出Java語言擾租歷的雛形。
Ⅸ java多線程下如何保證數據的一致性
以mysql來說,可能出現臟讀、不可重復讀以及幻讀,mysql默認設置是可重復讀,即一次事務中不會讀取到不同的數據。
可以做如下操作:
1)打開兩個客戶端,均設置為RR;
2)在一個事務中,查詢某個操作查到某份數據;比如是某個欄位version=1存在數據;
3)在另一個事務中,刪除這份version=1的數據;刪除後,在2所屬的事務中查詢數據是沒有變化的,還是存在version=1的數據;
4)當我們在2所屬的事務中繼續更新數據,那麼會發現更新不了,明明我們就看到了這份version=1的數據;
緩存一致性:
緩存一致,與什麼一致?是與資料庫一致,對外查詢每個時刻一致;所以在針對於緩存與資料庫之間該先更新哪一個呢?可能有人覺得我先更新資料庫,再更新緩存不就行了嗎?但是有想過個問題嗎?
當用戶已經支付成功了,更新到資料庫,但是呢?你還在緩存中顯示升宴森未支付,在用戶點擊頻率很高並且資料庫壓力過大,來不及同步到緩存時,那你是不是很尷尬吵畝,這就是典型的不一致了。此時用戶再支付,那你又告訴他已經支付了,那他會把你罵死的
那該怎麼來做呢?我們可以這樣,先更新緩存再更新資料庫,那麼存在什麼問題呢?
1)緩存更新成功,但是資料庫更新失敗,而被其祥和它的並發線程訪問到
2)緩存淘汰成功,但是資料庫更新失敗,這也會引發後期數據不一致